This year’s WWDC had a great talk on designing fluid interfaces. My main takeaway from this talk was how important gesture driven animations are, but not just that: how important velocity is while designing an animation. As to why this talk motivated me to write this article; somewhere in the talk they show this image:

Image from WWDC talk designing fluid interfaces

And this sparked my interest: “Could it really be this easy?”. Turns out it is, so in this article I’m going to try to shed some light on that subject, and help you to create animations that feel just right.

Let’s get started

As an example, I’m going to try to replicate the behaviour of PiP (picture in picture) view as seen in the FaceTime app. This view can be dragged and dropped in any of the corners of the screen, but when given a swipe it will take that velocity into account. Let’s get started on building that.

Note: I’m not going to show everything (like initialising the positions for the corners to snap to) since that would be a lot of boilerplate code. I’m just going to show what is necessary to put the pieces everything together and implement this principle in your own application(s).

The code shown below handles a naive way of dragging and dropping the view: when the drag gesture ends (so when the finger no longer touches the screen) the nearest corner is determined, and the view snaps to that position. All this code is placed in the UIView subclass of the PiP view, so properties like frame are readily available. The setupGestureRecognizer function is called when we initialise the View in the ViewController, the currentPosition property is used to save the corner the view is currently “snapped” to and the nearesCornerPosition function uses the current position of the view to determine the corner that is closest (and then returns that corner).

So there’s not too much magic going on over here. The only cool thing you’ll notice is that we’re using spring animations here. From the documentation:

Performs a view animation using a timing curve corresponding to the motion of a physical spring.

This has some properties, like duration , delay , dampingRatio and velocity that you can play around with a bit to get the right feel. These properties are explained in the WWDC talk mentioned above.

This is the result:

It works, but it doesn’t feel right. Let’s fix that.

Velocity and deceleration

Woo! Physics! Let’s make our PiP view less naive. Let’s scrap that; we’re going to make it smart. We’ll have it measure its own velocity, declare a deceleration rate and project the final position it will land in if it continues on that trajectory. Now we can use that position to determine to which corner to snap. Sounds good? Let’s get started!

Alright; let’s break this down. Dragging around the view is the same as it was before, but the real magic happens when the gesture.state == .ended block fires. We take the velocity from the gesture object, and we take the default decelerationRate from the UIScrollView class. We then project the final position with a function called project :

Does this look familiar?

Instead of using the frame.origin property to determine which corner to snap to, we now instead use the projected position we just created.

And that’s it!

So we’ve now covered a way to take velocity into account when building animations. I really recommend watching the WWDC talk mentioned above, since it gives a great explanation about the inner workings of the spring damping used in these animations.

One more thing

If you test the animations as shown above on a bigger phone (say, and iPhone X) you might notice the the animation feels a bit weird. I often do some phone specific checks to create an animation that is tailored to the device. In this case, a simple check like:

can really make a huge difference. In this case, the animation will play for 0.5 seconds if the device is smaller than the iPhone X, and will play longer on the iPhone X and all iPads. You can also play around with the spring properties to get the animation just right.