Animations in Swift

by keen

Container view transitions

If you want to perform an animated transition between two views, Apple provides a handful of default animations that are easy to create with just a small bit of code.

The trick to using these methods is that the transition needs to be performed in a parent container, which is typically just an invisible UIView that’s the size of the largest object you’re transitioning with. So performing this animation requires a little bit of setting up.

For example, to animate a transition between two colored UIViews we’ll use a third UIView as the container for the animation.

Lets set up all three views in the viewDidLoad() function…

Running the app now all you should see is a redSquare:

Now lets add an @IBAction from a button in the storyboard to trigger the actual animation and use the function UIView.transitionWithView which takes these options:

  • view: the view that the transition is animated within
  • duration: the number of seconds the transition will take
  • options: options for the transition (e.g. the animation style to use)
  • animations: a block defining changes to make as part of the transition; and
  • completion: another block this one defining code to run when the animation has completed.

The animation block should typically include the removal of one view, and the addition of the view (to the container) that is replacing it.

The transition from red square to blue square works as expected, but after that we’re stuck with the blue square.

This is because our @IBAction function is set up with the expectation that the redSquare is the visible square, and this is only true the first time we tap the animate button.

To fix this we’ll need to add some conditional logic that checks to see which square is currently visible to figure out if we should the transitioning from red-to-blue, or blue-to-red.

There are lots of ways this could be done, but lets use a feature of Swift called a ‘tuple’1.

Now we can alternate between the red and blue views!

Switching from one view to another is such a common task that so long as we don’t have anything else we also want to animate with the transition, Apple provides a slightly easier function that does the removeFromSuperview() and addSubView() for you automatically.

Here’s our simplified @IBAction function using this simplified transition function:

Now let’s try out some of the different default transition options that are available:

Keyframe block animations

Another new addition in iOS 7, instead of creating an animation by interpolating between a start value to an end value, this method allows us to define an by as many sub-parts as we want.

For one example of why you’d want to do this, consider how you would rotate an image a full 360 degrees.

Using our familiar basic animation functions you could attempt to animate the transform property like so:

But iOS can’t interpolate between the start and end values because they are equivalent!

To get around this, we’ll use animateKeyframesWithDuration to define the rotation in smaller parts, which iOS won’t get confused with, and then combine them all into a single animation.

To do the full rotation, lets break the animation into three parts, with each part rotating one third2 of the way around:

Now iOS has enough information to create the animation as we expected.

If you’re manually entering values for relativeStartTime & relativeDuration it’s easy to make a mistake, but if all you want to achieve is a smooth transition between each of the keyframes, you can enter CalculationModePaced as an option which ignores any values you’ve entered for relativeStartTime and relativeDuration and automatically figures out correct values for a consistent animation:

Moving an object along a bezier curve

A really fun animation to create is move the position of an object along a curve.

Our basic animation techniques make it easy to animate an object moving from point A to B, but to have an object move along the multiple points of a curve A,B,C,D,E we’ll need to use a keyframe-based animation again.

You could do this manually using the keyframe block function like we did for the rotation animation, but to get a nice smooth animation we’d have to define a lot of keyframes and it would get quickly get very complicated and messy.

Luckily, instead of assigning each keyframe manually, we can give iOS a bezier curve3 and the keyframes needed will be generated automatically.

This requires us to use more powerful animation features of iOS that are slightly more complicated, but not too hard once you get the general approach.

Now we have a single animation, lets use it multiple times to create a more complex scene.

Now we have multiple squares animating, but they all start at the same time so don’t look so great.

Lets set some more properties to the animation object that adds some randomness to how long the animation takes (so that some of the squares will move faster than others), and at what position of the animation it starts (so that they appear staggered).

Now our squares follow a bezier curve with with much more variation due to the randomness we’ve added to each animation.

From here, it’s not too much of a step to switch the redSquares to images and add a background to create an interesting organic animation like a school of fish or a flock of birds4.

Animating appearance of a bezier curve

Another useful technique to know that also uses an curve it to animate how much of the curve is drawn.

When we animated an object along a curve, the bezier path wasn’t actually shown on the screen, instead it was used as an input to the keyframe animation.

In this example, we’ll actually draw the curve to the screen, but animate how much of the curve is shown from 0 to 100%.

Lets add this code into an @IBAction function that’s triggered when a button is tapped.

This animation uses a very simple oval as a curve, but this technique can be applied to any curve at all. I’ve seen examples where someone has converted cursive text to create the illusion of a word being written, or you could combine it with animating an object along the same curve to show the path it’s taken while animating.

System default animation(s)

Another addition with iOS 7 is UIView.performSystemAnimation which for now only has UISystemAnimation.Delete as a valid option but I’m hoping that in the future Apple will add more standard system animations that can be easily created using this function.

Fin

Thank you Paul Webb for catching my bad Fin/fish joke in my last post5.

These animations start to get a little more complex so you might not succeed the first time around, but if you’re ever stuck, post a link to your code and I’d be happy to try and help!

Read More Swift Animation Posts...
Animations
Part 1
Transitions
Part 1
Transitions
Part 2
Transitions
Part 3

Notes

  1. Tuples are one of the reasons I love another programming language called Haskell. Most programming languages are designed so that a variable contains a single object. Tuples allow us to create an ad-hoc data structure that contains two (or more) objects of our choice.

  2. Splitting the animation into two halves is still potentially ambiguous since the rotation (in degrees) from 0 to 180 could equally be achieved either by moving clockwise or anti clockwise. It might work to define the rotation as (0 to 180 then 180 to 360) but since 0 and 360 are equivalent you might end up with the rotation backtracking on itself.

  3. Making bezier curves from control points isn’t easy to do if you’ve never worked with them outside of vector software before :(

    If you want to do it manually, the best place to start would be David Rönnqvist’s post: Thinking like a bezier path.

    Or, if you’re like me and that’s just too much, download PaintCode which (among other useful things) will automatically create Swift code for a bezier curve you’ve drawn on screen.

  4. For this animation I also added a random size for each fish, but instead of randomly adding variation to the speed of each fish I calculated the duration of each animation based off the size so that smaller fish take longer to complete one loop than the larger fish. This helps create an illusion of depth and perspective since closer objects should appear to move faster.

  5. For the record, I’m not a French New Wave fan: sadly it was a reference to Sharknado.