UILabel is a fairly robust class for displaying text of any kind. However, it doesn’t offer much in the way of animations and transitions. Changing a label’s text just updates its rendered bitmap immediately, but sometimes, it’s nice to have a simple transition effect between two text values. This Quick Bits post will demonstrate one such technique that I use quite a bit.

Crossfading two label values is simple enough using CATransition.1 However, I find that fading out an old value at the same time that a new value is being faded in is visually distracting; it’s difficult for the eye to track exactly what’s happening. Instead, it’s nice to quickly fade out the old value before fading in the next value:

let label = UILabel()
label.frame = CGRect(x: 0.0, y: 0.0, width: 400.0, height: 75.0)
label.backgroundColor = .white
label.font = .preferredFont(forTextStyle: UIFontTextStyleTitle1)
label.textAlignment = .center
label.text = "Hello, world!"

let fadeTransition = CATransition()
fadeTransition.duration = 0.2

    label.text = "Goodnight, moon..."
    label.layer.add(fadeTransition, forKey: kCATransition)

label.text = ""
label.layer.add(fadeTransition, forKey: kCATransition)


Two-stage fade transition for label text changes

Fading out a label's text value before fading in a new value

First, we apply a transition to the label while setting its text to an empty string. Using a CATransaction to capture its completion, we then repeat the process with the new string. This causes the old string to fade out before fading in the new string.

That’s about all it takes for a simple, two-stage fade transition. This trick can be applied to any layer, so image views are another good candidate.

  1. A crude explanation of how CATransition works is that it simply applies an animated change to a layer’s contents or visibility. Normally, if a layer is changed—i.e., given new contents or hidden—, Core Animation will render that change immediately. When a CATransition is attached to a layer, however, Core Animation will instead perform a simple animation that involves both the previously-rendered bitmap and the newly-rendered bitmap. This enables developers to achieve some sort of animated change to a layer in the absence of an actual animated property.