Advanced UIKit Animations In Swift - Digital Leaves
page-template-default,page,page-id-2887,qode-social-login-1.0,qode-restaurant-1.0,ajax_fade,page_not_loaded,,select-theme-ver-4.1,wpb-js-composer js-comp-ver-5.2,vc_responsive

Advanced UIKit Animations In SwiftOne of the main appeals of iOS when compared to other mobile platforms such as Android is the richness of its visual interface and its user experience. Even now with the incredible paradigm of Material Design, iOS still triumphs Android in people’s mind. To a great extent, this is due to iOS elegant animations. In this tutorial, I’m going to teach you how to perform beautiful UIKit animations in Swift, from the basics to the most advanced, interactive animations.

As always, you can download the whole sample project for the tutorial from my Github page.

Why, How And When To Use Animations

You should never include animations in your applications just for the sake of it. Also, don’t include animation because it makes things look cool either. Ideally, animations need to serve a purpose. They might be there for one or several of these reasons:

  • offer a visual clue to the user about the purpose or behavior of a visual element
  • reinforce a concrete visual interaction to help the user understand its meaning or purpose
  • offer feedback to the user after a visual interaction

In fact, wisely adding animations to your user interface can greatly improve the whole user experience, not just at a visual level. They should be sufficiently noticeable and meaningful. However, they should always be subtle enough not to interfere with the normal interaction flow of the user.

Conversely, overusing animations can confuse the user, or make your application look unrealistic, childish or incoherent.

Luckily for us, UIKit includes a rich and extensive set of methods and classes to help us animate our views.

What Can Be Animated

There are a lot of properties of a view that we can animate, including:

  • frame: modifying this property will allow us to change the view’s position and size, always relative to its superview.
  • bounds: modifying this property will allow us to modify the view’s size, as the bounds don’t depend on the superview.
  • center: modifying this property will change its position by changing its center, relative to its superview.
  • transform: the transform of the view allows us to specify 2D transformation such as rotations, scale or translate the view. Usually they can be combined to generate pretty interesting effects.
  • alpha: modifying this property will alter the view’s opacity.
    Modify this property to gradually change the transparency of the view.
  • backgroundColor: indeed, the background color of a view can be modified in an animated fashion.
  • contentStretch: this property allows us to modify how the contents of the view distribute and stretch to fill the available space.

In this article, we will focus in animating the frame of the view, hence modifying its position and size.

Animations in Swift and AutoLayout

As I describe in this article about AutoLayout Animations, generally speaking, you should no longer animate views using its frame or bounds properties directly. Here’s why:

Imagine that we have a normal view controller with our main view. Also, inside this view we have a yellow view. We pin this view to the top left corner and assign it a size of 100×75. Next, we animate some of the properties we saw earlier, including its position and size.

AutoLayout animations. Status of AutoLayout constraints after animation. Advanced UIKit Animations In Swift.

As a result of this animation, the current width, height and position of the yellow view change. However, the AutoLayout constraints haven’t changed. This means that the view is in an “unstable” situation: its position and size are “incorrect” according to its AutoLayout constraints. Hence, any layout operation will return the view back to its correct configuration. This happens, for instance, if we present and dismiss a view controller. If our view is inside a UITableViewCell, refreshing the cell will also rollback the animation. Rotating the device will also trigger an AutoLayout refresh.

I don’t know why Apple insists year after year on featuring animations based on direct position and size, when it may cause problems in an AutoLayout environment. Nevertheless, animating frames directly can still be valid for some scenarios. That’s why I am going to show you here how to do it correctly.

Thus, without further ado, let’s have a look at how to perform UIKit animations in Swift.

Basic UIKit Animations in Swift

First, let’s start with the basics. As you may already know if you have followed the AutoLayout Animations tutorial, the most basic way of animating a view is using UIView’s animate(withDuration:animations:completion).

For our sample app, let’s have a look at how to animate an square view down-to-top and back.

In order to go back to our original position, we will store the original position of our square in viewDidAppear in a variable called originalPosition. Then, it’s as simple as checking whether the square is in our original position or not, and animate it accordingly.

For our animation, we will modify the frame of the view, but only affect the vertical position of the view. We will use a negative offset for the Y axis that will make our view go over to a position relatively close to the top, no matter the device.

Additionally, to avoid the user messing around with our animation, we disable the animation button while the animation is in progress.

The animate method will process the modifications specified in the animations block in an anima

The completion block, after the animations block, is useful for performing actions after the animation is over. In our case, it’s the perfect place to enable our animation button again. The success variable here indicates whether the animation was successful or not. A false value probably means that some of the views didn’t end up in its supposed final position.

Using Animators

Apple introduced UIViewPropertyAnimator as a more convenient way to perform animations. While it’s true that animators offer a greater deal of control, most of the times, if you don’t need to stop the animation or do anything fancy, UIView’s animate is enough.

UIViewPropertyAnimator is a UIKit class that, appropriately enough, is used to animate properties. Let’s see how to obtain the same animation in our square view using a UIViewPropertyAnimator:

First, you create the animator:

Next, you can specify the animations that this animator will perform:

Optionally, you add some completion instructions to be executed after the animation ends:

Finally, you call startAnimation to trigger the animation.

The visual result of the animation is exactly the same as the previous one.

Animation Curves

You might have noticed that we specified a linear curve when initializing our animator. What does this curve mean? Well, this curve specifies how the animation progresses over time. The picture below depicts the available curves for UIKit.

Advanced UIKit Animations in Swift. Animation Curves.

The X axis represents the time, whereas the Y axis represents the progress of the animation. As a result, a linear curve progresses linearly as the time passes.

On the contrary, an “Ease in” curve starts the animation slowly and accelerates towards its end.

Conversely, an “Ease Out” curve starts the animation faster and decelerates towards the end.

Finally, an “EaseInOut” curve combines the properties of the two previous curves. It starts slowly, accelerates halfway through, and then decelerates nicely towards the end.

Specifying a curve other than linear smoothes our animations and makes them easier and somewhat more realistic to the eye. However, in order to have truly realistic results, we usually resort to Spring Animations.

Spring Animations in Swift

Spring animations mimic real life interactions between physical bodies much better. In order to perform spring animations in Swift with a UIViewPropertyAnimator, you use another initializer specifying the duration and the damping ratio.

Here’s our view being animated via a spring animation.

As you might notice, the effect is a lot more realistic and elegant.

The dumping ratio indicates the “resistance” of the view to being moved, just as if it was a physical body. The bigger the dumping ratio, the less the view will bounce. Thus, a dumping ratio close to zero will cause the view to bounce wildly, whereas a dumping ratio of 1 will behave closer to a non-spring animation.

Try several dumping ratios for your animations until you reach the desired effect. Oftentimes a little tweaking can make a huge difference.

Interactive Animations in Swift

Sometimes you need to add interactivity to your animations. Maybe you are presenting a new view to your users, and you want them to be able to pan to make it appear, but continue the animation once they release the finger until the view reaches its final destination.

This use case is very typical for iOS applications. In order to allow for that kind of interaction, we need to add a gesture recognizer to the view, and link the gesture recognition process with the progress of the animation. Let’s see how to create interactive animations in Swift.

Gesture Recognizers 101

A gesture recognizer, as its name indicates, is an object devoted to recognize a gesture performed by the user in a view. There are concrete gesture recognizers for all types of gestures in iOS: tap, pan, swipe, pinch… Every gesture recognizer has an action method that gets triggered when the gesture is recognized.

Additionally, every recognizer will be in a concrete state when the action method is invoked. These states, as per the Apple documentation, are:

  • possible: the recognizer has not yet recognized its gesture, but may be evaluating touch events. this is the default state.
  • began: the recognizer has received touches recognized as the gesture.
  • changed: the recognizer has received touches recognized as a change to the gesture.
  • ended: the recognizer has received touches recognized as the end of the gesture.
  • cancelled: the recognizer has received touches resulting in the cancellation of the gesture.
  • failed: the recognizer has received a touch sequence that can not be recognized as the gesture.

Most usually, you only need to worry about three: when the gesture is recognized (.began), when it changes (.changed) and when it ends (.ended).

Interaction Between Gesture Recognizers and Animations in Swift

In the case of an animation, we will do the following steps:

  • When the gesture begins, we will create the animation and stop it, because we don’t want it to continue unless the gesture progresses. In the case of a pan gesture, this happens when the user puts a finger in the surface of the screen and starts panning it.
  • Upon changes in the gesture recognition, we will update the status of the animation manually, but keep it paused. In the case of the pan gesture, the user is moving the finger through the surface of the screen, so we will update the animation on every little movement of the finger.
  • When the gesture ends, we will resume the animation, allowing it to end gracefully in its final state. In the case of the pan gesture, this happens when the user lifts its finger off the screen.

Adding The Gesture Recognizer To Our View

First, we will create a pan gesture recognizer, and add it to the view.

Interacting With The Animation

Then, the handlePan method will be called when the state of the recognizer changes.

Let’s go through this method step by step.

The Animation Begins

First, when the gesture begins, we will create and start the current animation. Immediately after, we will pause it.

This is the initializeAndStartCurrentAnimation method:

Also, we will store the current progress of the animation, initialized to the initial fractionComplete property of the animation (which is 0.0) to update it manually as the user moves its finger up the screen. The fractionComplete property goes from 0.0 to 1.0, and setting it manually affects the animated properties being animated.

Updating The Animation

Next, when the gesture changes, we will update the fractionComplete of the animation according to the translation of the finger between the starting and ending points.

Remember how we calculated the final frame for the square as:

Then, let’s say that self.view.frame.height, the max distance we can move our finger, is 100px. If we move our finger 20px up, we have covered 20% of the distance. Thus, we can calculate the percentage of progress for the animation as:

And of course we need to add our current progress (If we had gone through 20% of the distance previously and now we move another 20%, we will be at a total 40% progress in the animation).

This distanceTravelledInYAxis can be calculated as a translation in our view, thanks to the recognizer’s method translation(in:). This method gives us the distance (as a CGPoint with X and Y translation values) for the gesture change in a given view. As a result, the final modified progress is:

However, when we the square view has moved to the top, and animates back to the bottom, we will need to reverse the offset of the final position. Thus, we will use this translationFactor variable, that will start at -1 (the square will move up) and will dictate the direction of the movement.

Releasing The Animation

Finally, when the user releases the finger, we need to continue the animation until its reaches its final destination. We do that by means of the animator’s method continueAnimation(withTimingParameters:, durationFactor:).

Optionally, when resuming an animation, you can alter the curve, or the spring parameters of the animation from that moment on by using the withTimingParameters property. Let’s see an example in which we modify the curve, once the user releases the finger, to a non-spring EaseOut curve.

While modifying the animation this way can have quite interesting and amusing effects, as always, think about the meaning of the application and if it makes sense, instead of applying it for the sake of adding a cool effect.

Similarly, the durationFactor allows you to expand or shrink the time of the animation from the moment it continues. Experiment with this value, but don’t use it without a good reason.

Bouncing Back To The Original Position

To make the animation even more fun and realistic, we will add a “bounce back” resistance factor. We will modify the .ended recognition state so that, when we detect that the gesture has ended, if the distance travelled is less than half the total distance, the view will “bounce back” to its original position.

In order to achieve this, we will use the isReversed property of the animator, that allows us to reverse the animation.

This is the result.

Notice how the finger now controls the progress of the movement. Once released, though, the square view will continue all the way to the final destination, or bounce back, depending on the distance travelled.

Interruptible Animations in Swift

Apart from the bounce back effect, another awesome use of the isReversed property for animations in Swift, is the ability to interrupt the animation and reverse it. In order to do this, we will add another gesture recognizer, this time a UITapGestureRecognizer. We will configure it so that when it detects a tap in the square view when it’s being animated, it will reverse the animation.

First, we add the gesture recognizer and its action in viewWillAppear:

Then, in the handleTap method, we will call a method that will start the animation (if it hasn’t started already) or will reverse it (if it already exists).

The result really shows the richness of animations in Swift:

Where To Go From Here

In this tutorial, you learned how to perform UIKit Animations in Swift. We covered from basic animations to fully interactive and interruptible animations. The UIKit framework allows us to perform rich and expressive animations on many properties of UIViews, like position, size, etc.

However, in the context of modern applications, after the introduction of AutoLayout, views are no longer positioned by means of their frames, but using a set of AutoLayout constraint. As a result, it’s always better to perform animations on AutoLayout constraints, that will interact better with the rest of visual elements in your interfaces. This tutorial on AutoLayout animations in Swift will show you how to achieve this.

Additionally, you can of course download the “Advanced UIKit animations in Swift” project source code to get the examples used throughout this tutorial.

Before you continue...

Hi there! I created the Digital Tips List, the newsletter for Swift and iOS developers, to share my knowledge with you.

It features exclusive weekly tutorials on Swift and iOS development, Swift code snippets and the Digital Tip of the week.

Besides, If you join the list you'll receive the eBook: "Your First iOS App", that will teach you how to build your first iOS App in less than an hour with no prior Swift or iOS knowledge.

I hate spam, and I promise I'll keep your email address safe.