UIView Animations Tutorial: Practical Recipes

In this UIView animations tutorial, you’ll learn to build practical recipes for your iOS apps using the UIKit framework. By Nick Bonatsakis.

Leave a rating/review
Download materials
Save for later
Share
Update note: Nick Bonatsakis updated this tutorial for iOS 12, Xcode 10 and Swift 4.2. Fabio Budai wrote the original.

If you’ve ever paid close attention to how a great iOS app feels as you use it, you’ll quickly notice that subtle and fluid UIView animations are key to making the experience feel interactive.

While animation is usually not critical to the core functionality of your app, it can help guide and inform your users, gracefully reveal and dismiss parts of your UI and generally add a level of polish that can make your app stand out from the competition.

UIKit has some really powerful built-in UIView animations, and the latest Swift-based interfaces make using them really easy.

The tutorial team has already covered how to use UIView Animations in this UIView Animation Tutorial, so you might want to go through that tutorial first if you’re unfamiliar with the concepts.

This tutorial takes things a step further, walking you through a number of cool animation recipes that you can easily apply to your own apps.

Getting Started

Use the Download Materials button at the top or bottom of this tutorial to download the starter project. Open it in the latest version of Xcode. Build and run, and you should see a basic app that looks like this:

You can tap around on the various buttons, but you’ll find that at this point, it doesn’t do much of anything.

Before you start beautifying this app with sweet, sweet UIView animations, here’s a brief tour of what the starter project already includes:

  • ViewController.swift: Contains the main view controller that renders the UI you’ll animate in later steps. It includes empty @IBAction methods for each animation that you will add, as well as @IBOutlet properties for various UI elements that you’ll animate.
  • AnimationCurvePickerViewController.swift: Contains a view controller that shows a list of possible animation curves for the user to select from in a UITableView, as well as a delegate protocol to notify callers of the selection when the user taps a row.
  • FakeHUD.swift: Contains the UIView implementation for the XIB of the same name. It renders a HUD-style view with a progress indicator and label.

Now that you have the basic lay of the land, it’s time to dive into implementing your first animation. You’re going to look first at a couple of different animatable properties. These are pretty self explanatory — they are properties of a UIView which are able to be animated.

Frames

Create a new file by selecting File ▸ New ▸ File… and choose the iOS ▸ Swift File template. Name the file UIView+Animations.swift and click Create. You’re going to add an extension to UIView, which allows you to add some methods to an already existing class (UIView in this case) without subclassing it: a very neat and powerful way to expand an object’s functionality. You will put all the animation code in this extension.

Replace the newly created file’s content with the following code:

import UIKit

extension UIView {

  func move(to destination: CGPoint, duration: TimeInterval, 
            options: UIView.AnimationOptions) {
    UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
      self.center = destination
    }, completion: nil)
  }

}

This adds a new method to ALL instances of UIView, letting you animate moving the view itself from its current position to a new position. The time the animation takes is given by the duration parameter. Its units is seconds and is of type TimeInterval. Since TimeInterval is a typealias for Double, you have very fine control over how long the animation lasts. The options parameter relates to the animation curve used, which you’ll get more into that later on in the tutorial.

How does this work? The code uses the UIView.animate(withDuration:delay:options:animations:completion:) API on one of the view’s animatable properties: its frame. By simply changing the frame in the animations block, you tell Core Animation to move it to the new coordinates over the course of the duration. Core Animation will also automatically calculate and draw all the intermediate “steps” to get a smooth animation.

It’s as easy as that! You can see this in action by adding code to the view controller that powers the main interface.

Open ViewController.swift and wire up the first animation. To make the arrow move to a specified location, add the following code to moveTo(button:) method:

// 1
let destination = view.convert(button.center, from: button.superview)

// 2
movingButton.move(to: destination.applying(
                    CGAffineTransform(translationX: 0.0, y: -70.0)),
                  duration: 1.0,
                  options: selectedCurve.animationOption)

Not a ton of code, but here’s a breakdown of what it does:

  1. In this view controller, the movingButton (the view you want to move) is a subview of the root view, while each Move Here button is contained within a nested UIStackView. So to correctly animate the movingButton to the Move Here button that the user has tapped, you must first convert the coordinates of the button the user tapped to the coordinate space of the root view.
  2. Next, you call move(to:duration:options), which is in the UIView extension you added earlier. You call it on the movingButton (remember that UIButton is just a subclass of UIView, so inherits any UIView extension methods) to animate the button move. You pass a destination slightly above the tapped upon button, a duration of 1.0 seconds, and the currently selected animation curve. You will learn more about the curves later on.

Now build and run. Tap any of the “Move Here” buttons and watch in awe as the arrow smoothly moves to the button. Pretty cool for just a few lines of code, eh?

This recipe is useful to highlight a user’s selection or to slide in a bigger view — you put just a small part of a view on screen and allow the user to slide the rest of the view into the screen by tapping a button.

Transforms

One the most powerful animatable properties on a view is its transform. The transform is of type CGAffineTransform and represents a matrix that expresses how each pixel of the UIView should be modified by applying some matrix math.

Don’t worry, you don’t actually have to remember linear algebra, because there are some built-in transforms to make life nice and simple. Here, you’ll focus on two of them:

  • Scale: Allows you to scale a view up or down, optionally using different factors for the x and y axes. A value of 10.0 means “make the view 10 times bigger than the actual frame.” Please note that changing a transform’s scale will invalidate the frame property.
  • Rotate: Allows you to rotate a view by a given angle. It uses radians, the standard unit of angular measurement. One radian is equal to 180/π degrees.

It’s important to understand how UIView animations handle transforms: You can combine multiple transforms of different kinds, but iOS will “see” only the final result. So if you make a 360° (2π radians) rotation, the net effect is no rotation at all, and you won’t see any animation on your view!

Keep in mind that:

  • Rotations up to 180° are animated clockwise.
  • Rotations from 180° to 360° are animated counter-clockwise (it takes the shortest path, so 270° is rendered as a -90° rotation).
  • All rotations over a complete circle (360°) are ignored, and a 2π modulo is applied.

This will be easy to see when you try it out below.

Open UIView+Animations.swift and add the following method to the extension:

func rotate180(duration: TimeInterval, options: UIView.AnimationOptions) {
  UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
    self.transform = self.transform.rotated(by: CGFloat.pi)
  }, completion: nil)
}

This simply animates the view to rotate 180° over the specified number of seconds.

Time to see it in action! Jump back into ViewController.swift and fill out the rotate() method with the following code:

button.rotate180(duration: 1.0, options: selectedCurve.animationOption)

The above method is bound to the “touch up inside” action of the Arrow button, so it’s invoked any time you tap the arrow.

Build & run the app. Every time you tap the arrow button, you should see it flipping up/down (rotating 180°) with a smooth rotation. And you can still move it around!

This recipe may be useful for something like an on/off switch. You can even play with different angles to generate arrows for different directions using just one image.

A scale transformation is perfect for creating a zoom effect that can be great for picker views, where you want the picker to zoom in, choose something and then zoom out. And a picker is exactly what we need in the next section!