Joe
Joe

Reputation: 1958

How to animate UILabel's Text after delay?

I have a UIButton, and I would like to change its text by accessing its titleLabel attribute. However, the way I want the button to change text is by first shrinking down to a very tiny size, then changing instantly while it's invisible, then scaling back up. After looking through multiple posts on here, I have reached this:

 let changeText = CATransition();
    changeText.type = kCATransitionReveal;
    changeText.duration = 0.0;
    changeText.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionLinear);
    submitButton.titleLabel?.layer.add(changeText, forKey: "changeTextTransition");


    UIView.animateKeyframes(withDuration: 0.6, delay: 0, options: .calculationModeLinear, animations: {
        //Zzzeeeewwwwwwwwww
        UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5, animations: {
            self.submitButton.titleLabel?.transform = self.submitButton.titleLabel!.transform.scaledBy(x: 0.001, y: 0.001);
        })


        UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.0, animations: {
            self.submitButton.titleLabel?.text = "Green";
        })

        //Wwwwwweeeeeeyyyyyppp
        UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5, animations: {
            self.submitButton.titleLabel?.transform = self.submitButton.titleLabel!.transform.scaledBy(x: 1000, y: 1000);
        })
    }, completion: nil)

The problem is that this doesn't work. What I get is a quick flash of the words "New Text" as the label shrinks, and then when it scales back up, it's still "Old Text". It's so weird I can't even begin to wrap my head around what might be the cause. I think what's happening is that it plays the reveal transition on the new text before it even shrinks down (No idea why since I specified duration=0), then grows back the old text.

Here is what it looks like (with some background color change that I omitted above):

Weird Bug

Upvotes: 1

Views: 1028

Answers (1)

jrturton
jrturton

Reputation: 119242

First off, congratulations for including sound effects in your code comments, glad it's not just me that does that.

The text property of a label cannot be animated, so it is applied immediately, spoiling your animation.

One solution, which I use a lot for complex animations, is to use snapshots. At the start of the animation, create a snapshot of the label, then set the alpha of the label to zero and update the text. Then, animate the transforms of the label and snapshot together, when they're small, make the label visible and the snapshot invisible, then animate back up.

That sounds more complicated than it is, here's code to run it in a playground:

import UIKit
import PlaygroundSupport

let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
view.backgroundColor = .blue
PlaygroundPage.current.liveView = view

let label = UILabel(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
label.text = "Hello"
label.font = UIFont.systemFont(ofSize: 50)
label.textAlignment = .center
label.textColor = .white
view.addSubview(label)

let snapshot = label.snapshotView(afterScreenUpdates: true)!
view.addSubview(snapshot)
snapshot.frame = label.frame
label.alpha = 0
label.text = "Goodbye"

UIView.animateKeyframes(withDuration: 2, delay: 0, options: [.repeat, .autoreverse], animations: { 
    UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.45) {
        label.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
        snapshot.transform = label.transform
    }

    UIView.addKeyframe(withRelativeStartTime: 0.45, relativeDuration: 0.1) {
        label.alpha = 1.0
        snapshot.alpha = 0.0
    }

    UIView.addKeyframe(withRelativeStartTime: 0.55, relativeDuration: 0.45) {
        label.transform = CGAffineTransform.identity
    }
}) { _ in
    snapshot.removeFromSuperview()
}

Which gives you this result:

enter image description here

It's not clear to me what you are trying to do with the CATransition - unless there's another effect you're looking for as well, that isn't helping your cause.

Upvotes: 3

Related Questions