How to Create a Draggable Floating View in Swift
Add an interesting UI element to your app
Long story short, on our latest project, our team has to implement a floating view that can be dragged freely on the screen. For those who have an Android development background, think of it as a floating action button lookalike, but instead of staying still on certain parts of the screen, it can be dragged freely!
For those who don’t, have a look at these images :
The floating view is circled in red, as shown in the two images above.
After conducting some research, we found out that it was not that hard to implement it from scratch on an iOS app. This tutorial will cover every single thing you need to create one.
Note: Since I have not found the official name for this component on Apple’s HIG, I will just continue to call it a draggable view in this article.
Preparation
Create an iOS project on Xcode, choose storyboard as the project’s interface and UIKit App Delegate as its life cycle. Then we end up with the usual Xcode starter code that you love so much:
Then, go to Main.storyboard
, add a UIView
, and place it somewhere on the screen. You are free to decide where to put the view. For example, mine would be:
For simplicity’s sake, our draggable view will just be a circular view with some background colour on it. You could always go further by customizing it (e.g. by adding an image or something else).
What we have to do next is to connect our newly made view to the ViewController
:
If we run our application right now, we will see a little red box on the screen.
Let’s Get Started
In order to make our view draggable, we have to add a gesture recognizer called UIPanGestureRecognizer
.
Apple’s explanation of UIPanGestureRecognizer
is quite straightforward:
“A discrete gesture recognizer that interprets panning gestures.
…
Clients of this class can, in their action methods, query the
UIPanGestureRecognizer
object for the current translation of the gesture (translation(in:)) and the velocity of the translation (velocity(in:)).”
In simpler terms, this gesture can detect any translation that happens on the view, even enabling you to acquire its attributes such as velocity, final location, etc.
Let’s try to implement it on our ViewController
:
Here’s the play-by-play :
- On line 16, we set a
UIPanGestureRecognizer
to our draggable view, where we also made a callback function for our recognizer (which is called every time the panning event is emitted). - On the handler function, we simply print the gesture’s current location.
Try to run the application, then drag the view freely. Notice that although our view is not moving anywhere, we can see some kind of tuple on the debugging console, which is the current gesture location given in a coordinate. We’re on track to achieve our goal!
Now What?
Now that we have set a gesture recognizer, all we have to do is to update our view’s location. And since we already have our final location from the handler function, let’s just reuse that.
Add this code to our ViewController
:
In the code above:
- On line 20, we get the gesture’s current location.
- On line 21, we assign the gesture view that sent the panning event (our draggable view) to a variable.
- We then update the view’s center with the current location retrieved before.
If you try to run the app again, our view is eventually draggable. Yay!
But something is not right: Although we successfully made our view draggable, we can drag it beyond the screen, which is not a normal behaviour.
Besides that, the normal draggable view has the ability to drag itself to the nearest side of the screen when the user stops dragging, while ours does not.
So what can we do about it?
Actually, to achieve this behaviour, we only need to do a little workaround. We can apply some logic when the user stops dragging. Add this code to our ViewController
:
Here’s the logic :
- Starting on line 24, we add some logic to our handler to make the view have the behaviour we expect.
- We check whether the user has stopped dragging, then we do a comparison between the current view’s
midX
position and its superview’s width divided by half. We do the comparison to determine whether the current view is closer to its superview’s left or right side. - If the view’s
midX
is greater than or equal to half the width of its superview (closer to the right side of the screen), we then update itsX
position as its superview width minus 40. This means that our view’s final location will be located at 40pt from its superview’s trailing. - If it is closer to the left screen, we then update its
X
position to40
. This means that our view’s final location will be located 40pt away from its superview trailing.
Try to run the app. Voila! Our view now behaves as expected:
Conclusion
As you can see, creating a draggable view on iOS is not as hard as it seems. We only need to implement some logic regarding the final position of the view.
Happy coding!