Animations in iOS offer functional context to users and provide developers with a simple way to bring designs to life. While Apple provides two common methods for animations, CAAnimations and
UIView.animateWithDuration:animations:, they either sacrifice flexibility or create a lot of boilerplate code. That’s why at Savvy Apps we advocate learning the components and concepts of animations. This approach allows developers the freedom to find new ways to do animations. In this post, we define the components of an animation, as well as provide tips for creating and experimenting with interactive animations.
Dissecting an Animation
To understand how animations work you need to know the components of an animation. These are the basic steps that you will need to take to create your own animation system.
Establish the Purpose of the Animation
The first step in creating any animation is determining what it is you're looking to accomplish with your animation. Your animation can serve one or a number of purposes. Do you want it to make a certain flow or part of the app feel more natural? Do you want that little extra touch to provide delight for users? Animations can also serve a functional role in your app by providing important context for users. Arguably the most effective animations clue users in on what's happening in the app and what to do next.
Take this audio player animation we created in CatoAudio for The Cato Institute. The animation of the player expanding up from the bottom to fill the screen helps the user understand that the player is the topmost view of the app. The animation suggests that the user can close the view and access additional content by dragging the player down to its previous position. This focus on providing contextual functionality with animations informed many of our navigation decisions in CatoAudio.
Decide When to Update Your Content
To create the illusion of movement in an animation you need to make changes to your content several times per second. That requires you to know when to perform those changes. Ideally, you'll want to perform the changes whenever there is a change to be performed but not more often than that. Adding more changes than you need will only spend extra processing time on something that won’t have an effect.
The simplest way to perform the changes is to use a CADisplayLink. The display link sends a message whenever the screen is going to refresh, which allows you to perform changes to your content exactly once per frame. When the animation is finished you can either pause the display link or disable it.
Using a continuous gesture recognizer, like a pan, pinch, or rotation recognizer, is another way to identify when you should perform changes to your content. The gesture recognizer forces you to accept that you won’t be trying to perform those changes when the user hasn’t moved their finger, and when there aren’t any changes to perform. A more advanced way is to use the scrollViewDidScroll: delegate method of a UIScrollView. We cover how you can tap into gesture recognizers and the UIScrollView behavior later in this article.
Define the Progress of Your Animation
In addition to knowing when to update your content, you need to establish what about your content will actually change and how it will do so over time. The progress of the animation is usually stored as a floating point value in the [0,1] range, where 0 is the initial state and 1 the final state. To determine the progress of your animation you need to establish the following items.
The beginning and end of your animation. It’s a good idea to normalize the progress of your animation to the [0,1] range. This makes it easier to interpolate properties and more obvious where the animation progress currently is.
The rules of your animation. That is, how will the content animate? Will it translate? Scale? Rotate? Your animation's rules will also determine its animation curve. This specifies the velocity of the animation at a given point in time. A linear curve will result in the animation being executed at a constant velocity throughout the animation, and other curves can be used to give an effect of acceleration or bounce. Keep in mind that different situations will call for different animation curves.
In this visualization, the top circle is traveling in a linear animation curve, the middle circle is traveling in an easeInOutCubic curve, and the bottom circle is traveling in an easeOutBounce curve. There are many other types of easings you can use to make your animations feel more natural.
The duration of your animation. This can be either a fixed duration (for example, two seconds) or depend on an external variable, like how long it takes a user to drag their finger along the screen.
Once you’ve identified all of these components for your animation, you can figure out the best way to animate your content depending on the situation and the result you want.
Frameworks for Improving Your Simple Animations
At Savvy Apps we created SAAnimationView, a framework that allows us to quickly and easily create an animation programatically. It uses CADisplayLink to update every frame whenever the animation is not paused. Unlike other frameworks it doesn't rely on images, can be paused and played forwards or backwards, sped up and down, and is easy to alter. We used it to create this animation for CatoAudio.
We plan on releasing this framework to the public in the near future but are currently focused on having it peer reviewed and tested. If you're interested in trying it out before we release it to the public, drop us a note on our contact page.
You can also take advantage of the animation curves in the INTUAnimationEngine framework to improve your animations. For example, if you have a square that is moving horizontally and being drawn from the center, instead of calculating the center like
center = CGPointMake(progress * rectWidth, y)
you can calculate it as follows:
center = CGPointMake(INTUEaseInOutCubic(progress) * rectWidth, y).
This will apply an easeInOutCubic curve to your animation, where the movement will be slower at the beginning and the end, and faster in the middle.
Creating Animations That React to User Input
To create more depth to an application you can add animations that react to or interact with user input. Making an image follow the finger of the user is simple enough, how about transforming the contents of a view controller when the user drags the finger along the screen?
Using a Scroll View to Animate
UIScrollView is one of the backbones of UIKit and iOS. It is used in table views, collection views, web views, and more. The iOS scroll view has some very distinct behaviors, like the way it bounces when it reaches the edge of the content or the way it decelerates when the user stops dragging. These behaviors are hard to replicate. Even if you did, if Apple were to alter any of them, yours wouldn’t feel natural anymore. For these reasons we prefer to use scroll view for anything that scrolls.
Like we mentioned before, the
viewDidScroll: delegate method is ideal to update your animation because it’s updated whenever the contentOffset property of the scroll view changes. You can also use the contentOffset and contentSize properties to calculate the animation progress. For example, if you want to animate as your scrollView scrolls horizontally, you can calculate the progress as
progress = scrollView.contentOffset.x / (scrollView.contentSize.width - scrollView.bounds.size.width).
Now you only need to add your animation logic and your animation will react to the user dragging the scroll view. In the example to the left you can see how the page dots are animated as the content is dragged in the screen. The animation progress in this case goes from 0 to 3 (the number of page dots), but only because the animation is divided in three animations, one for each dot. Each of those animations can go from -1 to 1, and they are also split into two animations. The first one is when the progress is between -1 and 0, and is where the page dot goes from empty to full. In this case we add 1 to the value to achieve a [0, 1] range. The second is when the value is between 0 and 1, and it's where the check mark is drawn as the user scrolls the page, with 0 being no check mark and 1 being the full length of the check mark being drawn.
If you're clever about it, you can even support the bounce that scroll view does when you reach the edge. Say you want to utilize the drag and bounce behaviors of a scroll view, but you don’t need one in your view hierarchy. Start by creating one and configuring it. Then, instead of adding the scroll view to your view, you can add the scrollView’s panGestureRecognizer to the view where you want to receive the touches. This way you’ll receive the delegate calls as if the scroll view was scrolling, without having a scroll view on top of your view.
This is another example of using a scroll view to animate content. As we scroll, based on the contentOffset we calculate the index of the button that is in the middle, and get the progress of the animation where 0 would be when that button is on the left of the Leap logo and 1 when the button should be on the right. Then we use a sine curve to calculate the vertical offset. The beauty of the sine curve is that the y value, when the x value goes from 0 to PI, makes a nice curve that reaches 1 right in the middle with it beginning and ending at 0. Finally, we use the same progress to offset the button horizontally to make sure it doesn’t overlap with the Leap logo. All of this results in a nice leaping animation.
Using a Gesture Recognizer to Animate
As mentioned earlier, using a gesture recognizer to animate your content while the user interacts with it is also a great idea. The first thing you need to do is to make sure you are using a continuous recognizer. Pinch, rotation, and pan recognizers are continuous, this means that they will send messages as the gesture is being recognized, allowing you to update your animation while the gesture is being recognized. Gesture recognizers like swipe and tap are not continuous, meaning they will only send a message once the gesture has finalized. This is not helpful if you want to perform an animation while the gesture is happening, but can be useful if you want to trigger an animation after the gesture has been completed.
We used a pan gesture recognizer in CatoAudio to allow the users to drag the mini player into a full player. You can see how the views move around the mini player as the pan gesture is executed on the iPad.
Knowing all the components of an animation and how best to have animations interact with users gives you more options for creating unique animations that aren't limited by frameworks. We hope these tips empower you to try more advanced animation concepts to better bring your apps to life.
Join 20,000+ Other Readers
Sign up to be notified of new blog posts and be the first to receive helpful app goodies from Savvy Apps!