How To Create an Elastic Animation with Swift

Learn how to make a custom text field with an elastic bouncing animation in this iOS tutorial. By Daniel Tavares.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

UIView Spring Animations

Apple is really good at adding new features in every iOS release, and spring animations are one of its recent inclusions that makes it easy to up your app’s WOW factor.

It allows you to animate elements with custom damping and velocity, making it more special and bouncy!

Note: If you would like to master animations, check out iOS Animations by Tutorials.

Add the following method to ElasticView.swift to get those control points moving:

func animateControlPoints() {  
  //1
  let overshootAmount : CGFloat = 10.0
  // 2
  UIView.animateWithDuration(0.25, delay: 0.0, usingSpringWithDamping: 0.9, initialSpringVelocity: 1.5,
    options: nil, animations: {
    // 3
    self.topControlPointView.center.y -= overshootAmount
    self.leftControlPointView.center.x -= overshootAmount
    self.bottomControlPointView.center.y += overshootAmount
    self.rightControlPointView.center.x += overshootAmount
  },
  completion: { _ in
    // 4
    UIView.animateWithDuration(0.45, delay: 0.0, usingSpringWithDamping: 0.15, initialSpringVelocity: 5.5,
      options: nil, animations: {
        // 5
        self.positionControlPoints()
      }, 
      completion: { _ in
        // 6
        self.stopUpdateLoop()
      })
  })
}

Here’s the step-by-step breakdown:

  1. overshootAmount is the amount the control points will move by.
  2. Wraps the upcoming UI changes in a spring animation that lasts a quarter of a second. If you’re new to spring animations but good at physics, check out the UIView class reference for a detailed explanation of the damping and velocity variables. For the rest of us non-rocket scientists, just know that these variables control how the animation bounces. It’s normal to play with the numbers to find a configuration that feels right.
  3. Move the control points up, left, down or right – this will be animated.
  4. Create another spring animation to bounce everything back.
  5. Reset the control point positions – this will also be animated.
  6. Stop the display link once things stop moving.

So far, you haven’t called animateControlPoints. The main purpose of your custom control is to be animated once you tap on it, so the best place to call the above method is inside touchedBegan.

Add the following to it:

override func touchesBegan(touches: Set, withEvent event: UIEvent) {
  startUpdateLoop()
  animateControlPoints()
}

Build and run, and then tap your view. Voila! :]

Elastic Magic

Refactoring and Polishing

Now you’ve gotten a glimpse of the cool animation, but you have a little more work to do to make your ElasticView more abstract.

The first obstacle to clear out is overshootAmount. At the moment, it’s hardcoded with a value of 10, but it would be great to change its value both programmatically and via Interface Builder.

IBDesignable

One of the new features of Xcode 6.0 is @IBInspectable, which is a nice way of setting custom properties via interface builder.

Note: If you want to learn more about @IBInspectable, then please read Modern Core Graphics with Swift by Caroline Begbie.

You’re going to take advantage of this awesome new feature by adding overshootAmount as an @IBInspectable property, so that each ElasticView you create can have a different value.

Add the following variable to ElasticView:

@IBInspectable var overshootAmount : CGFloat = 10

Reference the property in animateControlPoints() by replacing this line:

let overshootAmount : CGFloat = 10.0

With this line:

let overshootAmount = self.overshootAmount

Head over to Main.storyboard, click on ElasticView and select the Attributes Inspector tab.

lBInspectable

You’ll notice a new tab that shows the name of your view and an input field named Overshoot A…

For every variable you declare with @IBInspectable, you’ll see a new input field in Interface Builder where you can edit its value.

To see this in action, duplicate ElasticView so you end up with two views and place the new one above your current view, like so.

m

Change the value of Overshoot Amount in the original view to 20 and 40 in your new view.

Build and run. Tap on both views to see the difference. As you can see, the animations vary slightly, and are dependant on the amount you’ve entered in interface builder.

n

Try changing the value to -40 instead of 40, and see what happens. You can see the control points animating inwards but the background doesn’t seem to be changing.

o

Are you ready to fix that on your own? I bet you are!

I’ll give you one clue: You’ll need to change something inside the setupComponents method. Try it on your own, but if you get stuck, take a peek at the solution below.

[spoiler title=”Solution”]

// You have to change the background color of your view after the elasticShape is created, otherwise the view and layer have the same color
backgroundColor = UIColor.clearColor()
clipsToBounds = false

[/spoiler]

Well done, you’ve finally completed your ElasticView.

Now that you have an ElasticView, you can embed it in different controls, such as text fields or buttons.

Making an Elastic UITextfield

Now that you have built the core functionality of your elastic view, the next task is to embed it into a custom text field.

Right-click the ElasticUI group in the project navigator, and then select New File…. Select the iOS/Source/Cocoa Touch Class template and click Next.

Call the class ElasticTextField, enter UITextfield into the Subclass of field and make sure the language is Swift. Click Next and then Create.

Open up ElasticTextField.swift and replace its contents with the following:

import UIKit

class ElasticTextField: UITextField {
  
  // 1
  var elasticView : ElasticView!
  
  // 2
  @IBInspectable var overshootAmount: CGFloat = 10 {
    didSet {
      elasticView.overshootAmount = overshootAmount
    }
  }
  
  // 3
  override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
  }
  
  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setupView()
  }

  // 4
  func setupView() {
    // A
    clipsToBounds = false
    borderStyle = .None

    // B
    elasticView = ElasticView(frame: bounds)
    elasticView.backgroundColor = backgroundColor
    addSubview(elasticView)

    // C
    backgroundColor = UIColor.clearColor()
    
    // D
    elasticView.userInteractionEnabled = false
  }
  
  // 5
  override func touchesBegan(touches: Set, withEvent event: UIEvent) {
    elasticView.touchesBegan(touches, withEvent: event)
  }
}

There’s a lot going on in there! Here’s a step-by-step breakdown:

  1. This is A property to hold your ElasticView.
  2. An IBInspectable variable called overshootAmount, so you can change your control’s elasticity via Interface Builder. It overrides didSet and just sets the overshootAmount of your elastic view.
  3. The standard initializers for the class, both so which call a set up method.
  4. This is where you set up the text field. Let’s break it down even further:
    1. Changes clipsToBounds to false. This lets the elastic view go beyond its parent’s bounds and changes the border style of the UITextField to .None to flatten the control.
    2. Creates and adds ElasticView as a subview of your control.
    3. Changes the backgroundColor of your control to be clear; you do this because you want the ElasticView to decide the color.
    4. Finally, this sets the ElasticView’s userInteractionEnabled to false. Otherwise, it steals touches from your control.
  5. Overrides touchesBegan and forwards it to your ElasticView so it can animate. :]
  1. Changes clipsToBounds to false. This lets the elastic view go beyond its parent’s bounds and changes the border style of the UITextField to .None to flatten the control.
  2. Creates and adds ElasticView as a subview of your control.
  3. Changes the backgroundColor of your control to be clear; you do this because you want the ElasticView to decide the color.
  4. Finally, this sets the ElasticView’s userInteractionEnabled to false. Otherwise, it steals touches from your control.

Head over to Main.storyboard, select both instances of UITextfield and change their classes from UITextField to ElasticTextField in the Identity Inspector.

Also, make sure you delete both instances of ElasticView that you added for testing purposes.

textfields

Build and run. Tap on your textfield and notice how it doesn’t actually work:

Elastic UI

The reason is that when you create an ElasticView in code, it gets a clear background color, which is passed on to the shape layer.

To correct this, you need a way to forward the color to the shape layer whenever you set a new background color on your view.

Daniel Tavares

Contributors

Daniel Tavares

Author

Over 300 content creators. Join our team.