Animating the text size and opacity in iOS using Swift

For certain tasks in iOS development there are ample examples in Objective-C but not Swift. This can be a problem when API calls take structures as arguments as the Swift compiler performs more and different type-safety checks. An additional challenge was that the compiler errors can be a bit vague about what it is expected.

An example of this we came across recently was using CAKeyframeAnimation in a Swift iOS application. CAKeyframeAnimation was used in the case to increase the size of a label so that, when combined with a fade animation, would cause a label on a view to increase in size and opacity simultaneously.

Fade Animation

The fade animation was fairly simple to implement in Swift.

//create a CABasicAnimation that fades from 0 to 1 opacity over 3 seconds
var fadeAnimation = CABasicAnimation(keyPath: "opacity")
fadeAnimation.fromValue = 0.0
fadeAnimation.toValue = 1.0
fadeAnimation.duration = 3.0

Text Size Animation

To animate the change in text size, we need to use CAKeyframeAnimation as there is no provided keyPath in CABasicAnimation that controls text size or any other text attributes.

// create a CAKeyframeAnimation with a keyPath of "transform"
var scaleAnimation = CAKeyframeAnimation(keyPath: "transform")

So far so good. They keyPath "transform" indicates that we will be applying a transform to some value as part of the animation.

Now here comes the part that took a little research. The CAKeyframeAnimation class takes an array of values for the transformation. This series of transformation values to describe each step of the animation. In this case, we only have two values that we are going between 10% and 100%. We start at 10% and smoothly transition to 100% of the text size. The CAKeyframeAnimation class has a function called values that is defined as:

var values: [AnyObject]!

First we tried:

scaleAnimation.values = [CATransform3dMakeScale(0.1, 0.1, 0), CATransform3dMakeScale(1.0, 1.0, 0)]

But this gave a compiler error of:

Use of unresolved identifier 'CATransform3dMakeScale'

Further search revealed that the .values function is expecting an array of NSValue objects. So we tried:

scaleAnimation.values = [NSValue(CATransform3DMakeScale(0.1, 01.0)), NSValue(CATransform3DMakeScale(1.0, 1.0, 0))]

Changing the compiler error to:

Missing argument label 'CATransform3D' in call 

The Fix-it tip was "Insert CATransform3D:" which changed the call to:

// set the CAKeyframeAnimation to go from 10% to 100% scale
scaleAnimation.values = [NSValue(CATransform3D: CATransform3DMakeScale(0.1, 0.1, 1)), NSValue(CATransform3D: CATransform3DMakeScale(1, 1, 1))]

To finish it off, we specified an "Ease Out" timing function and set a duration of 3 seconds.

// specify and "Ease Out" timing function
scaleAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
// set the duration of the animation for 3 seconds
scaleAnimation.duration = 3

Finally, we added both animations to the Label object's layer:

// add both animations to the Label
growingLabel.layer.addAnimation(scaleAnimation, forKey: "transform")

growingLabel.layer.addAnimation(fadeAnimation, forKey: "opacity")

The result was a text label that faded in and grew from 7.2 points to 72 points over 3 seconds while going from transparent to fully opaque over the same 3 second interval.