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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How To Create an Elastic Animation with Swift
20 mins
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.
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:
-
overshootAmount
is the amount the control points will move by. - 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. - Move the control points up, left, down or right – this will be animated.
- Create another spring animation to bounce everything back.
- Reset the control point positions – this will also be animated.
- 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! :]
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.
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.
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.
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.
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.
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.
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:
- This is A property to hold your ElasticView.
- An
IBInspectable
variable calledovershootAmount
, so you can change your control’s elasticity via Interface Builder. It overridesdidSet
and just sets theovershootAmount
of your elastic view. - The standard initializers for the class, both so which call a set up method.
- This is where you set up the text field. Let’s break it down even further:
- Changes
clipsToBounds
tofalse
. This lets the elastic view go beyond its parent’s bounds and changes the border style of theUITextField
to.None
to flatten the control. - Creates and adds
ElasticView
as a subview of your control. - Changes the
backgroundColor
of your control to be clear; you do this because you want the ElasticView to decide the color. - Finally, this sets the ElasticView’s
userInteractionEnabled
tofalse
. Otherwise, it steals touches from your control. - Overrides
touchesBegan
and forwards it to yourElasticView
so it can animate. :]
- Changes
clipsToBounds
tofalse
. This lets the elastic view go beyond its parent’s bounds and changes the border style of theUITextField
to.None
to flatten the control. - Creates and adds
ElasticView
as a subview of your control. - Changes the
backgroundColor
of your control to be clear; you do this because you want the ElasticView to decide the color. - Finally, this sets the ElasticView’s
userInteractionEnabled
tofalse
. 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.
Build and run. Tap on your textfield and notice how it doesn’t actually work:
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.