81

I'm new to iPhone and Mac programming (developed for Windows before), and I've got a question:

How do I animate the text property of an UILabel between two numbers, e.g. from 5 to 80 in an Ease-Out style? Is it possible with CoreAnimation? I have been searching on Google for an hour, but I haven't found anything solving my problem. What I want: Animate the users money for a simple game. It doesn't look very nice when it just goes from 50 to 100 or something like that without animation.

Anyone having an idea how to do that?

Thanks!

Andrea Gottardo
  • 1,329
  • 11
  • 23
Markus Kasten
  • 1,170
  • 1
  • 10
  • 15
  • 2
    This is an old question but Pop (Facebook animation framework) would be a good solution. You could animate the text property directly. – jrturton May 14 '14 at 07:12
  • Possible duplicate of [Animate text change in UILabel](http://stackoverflow.com/questions/3073520/animate-text-change-in-uilabel) – eonil Dec 24 '15 at 14:53

6 Answers6

160

You can use the automatic transitions. It's working perfectly well :

// Add transition (must be called after myLabel has been displayed)
 CATransition *animation = [CATransition animation];
animation.duration = 1.0;
animation.type = kCATransitionFade;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[myLabel.layer addAnimation:animation forKey:@"changeTextTransition"];

// Change the text
myLabel.text = newText;

This code works if myLabel is already displayed. If not myLabel.layer will be nil and the animation will not be added to the object.


in Swift 4 that would be:

let animation: CATransition = CATransition()
animation.duration = 1.0
animation.type = kCATransitionFade
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
myLabel.layer.add(animation, forKey: "changeTextTransition")
Andrea Gottardo
  • 1,329
  • 11
  • 23
CedricSoubrie
  • 6,657
  • 2
  • 39
  • 44
  • 2
    I tried this (ensuring that the layer is not nil when the animation is added), but the text still doesn't animate. Any other gotchas? – elsurudo Jan 03 '13 at 13:06
  • 5
    Just a side note, you have to add the animation right before you change the text each time you want to change the text and have the fade effect happen. You don't however have to instantiate a new Transition each time, the same instance can be reused over and over. – Lance Jun 06 '13 at 19:03
  • 2
    The question was how to animate the numbers e.g. incrementing them in value, not graphically fading between the two. Use PRTween: https://github.com/shu223/TweenDemo/tree/7b10a8803df174791336b7f74e2c6a8e5bf5fe51/libs/PRTween – jowie Jun 11 '13 at 15:06
  • 14
    Actually, if you set `removedOnCompletion` to `NO` on the instance of `CATransition`, every change to the label's `text` will be animated. – Mark Adams Nov 16 '13 at 18:44
  • didn't work for me: I use this code when change text from slider value - no luck =( – WINSergey Dec 07 '14 at 18:19
  • How do you even know the key for this? I mean there are some common keys for layer property like `opacity`, `position`, etc. But where do you find the `changeTextTransition`?? I can't find any document for this. – kientux Jan 31 '17 at 20:24
  • @kientux No idea where a doc could be and if there is any. Found that key on a tutorial years ago. – CedricSoubrie Feb 02 '17 at 10:18
  • 1
    @kientux There's nothing special about the key `changeTextTransition`. It's simply [a string that identifies the animation](https://developer.apple.com/reference/quartzcore/calayer/1410848-add), which means it's a string that you can use later to identify an animation that you previously added. If you don't need to be able to identify your animation later, you can just specify `nil`. – jamesk Mar 01 '17 at 00:15
27

It works well!

Objective-C

[UIView transitionWithView:self.label 
                  duration:.5f 
                   options:UIViewAnimationOptionCurveEaseInOut | 
                           UIViewAnimationOptionTransitionCrossDissolve 
                animations:^{

    self.label.text = rand() % 2 ? @"111!" : @"42";

} completion:nil];

Swift 2

UIView.transitionWithView(label, duration: 0.25, options: [.CurveEaseInOut, .TransitionCrossDissolve], animations: {
    self.label.text = (arc4random() % 2 == 0) ? "111" : "222"
}, completion: nil)

Swift 3, 4, 5

UIView.transition(with: label, duration: 0.25, options: [.curveEaseInOut, .transitionCrossDissolve], animations: {
    self.label.text = (arc4random() % 2 == 0) ? "111" : "222"
}, completion: nil)
Karen Hovhannisyan
  • 1,140
  • 2
  • 21
  • 31
Anton Gaenko
  • 8,929
  • 6
  • 44
  • 39
7

I found a great engine for tweening values with a variety of different timing functions called PRTween. Install the classes and create some code along these lines:

- (IBAction)tweenValue
{
    [[PRTween sharedInstance] removeTweenOperation:activeTweenOperation];
    PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:0.0 endValue:100.0 duration:1.0];
    activeTweenOperation = [[PRTween sharedInstance] addTweenPeriod:period
                                                             target:self
                                                           selector:@selector(update:)
                                                     timingFunction:&PRTweenTimingFunctionCircOut];
}

- (void)update:(PRTweenPeriod*)period
{
    self.animatingView.center = CGPointMake(period.tweenedValue + 100.0, 200.0);
    self.valueLabel.text = [NSString stringWithFormat:@"%.2f", period.tweenedValue];
}

Works a treat for me. :)

jowie
  • 8,028
  • 8
  • 55
  • 94
5

If you kind of want it to count up and down with the new number pushing the previous number away (like a ticker or something):

let animation = CATransition()
animation.removedOnCompletion = true
animation.duration = 0.2
animation.type = kCATransitionPush
animation.subtype = newValue > value ? kCATransitionFromTop : kCATransitionFromBottom
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
valueLabel.layer.addAnimation(animation, forKey:"changeTextTransition")
Adam Waite
  • 19,175
  • 22
  • 126
  • 148
  • Hey! Thanks for your answer! This works pretty neat. I have only on further question. Do you know how to animate only parts of the text? Like the 3rd character and let the rest be unchanged? I would like to implement a label that shows numbers. If the value changes only the digits shall animate, that actually changed. – Lars Petersen Mar 17 '18 at 17:01
  • Personally I'd look into using CoreGraphics and CoreAnimation for this kind of thing. Or you could cheat and string a couple of labels together? Depends on how complex you string is. – Adam Waite Mar 21 '18 at 11:53
3

In Swift 2.0, using the UIView.transitionWithView() method:

UIView.transitionWithView(self.payPeriodSummaryLabel,
        duration: 0.2,
        options: [.CurveEaseInOut, .TransitionCrossDissolve],
        animations: { () -> Void in
            self.label.text = "your text value"
        }, completion: nil)
brandonscript
  • 68,675
  • 32
  • 163
  • 220
1

another simple alternative

extension UILabel {    
    func countAnimation(upto: Double) {
        let from: Double = text?.replace(string: ",", replacement: ".").components(separatedBy: CharacterSet.init(charactersIn: "-0123456789.").inverted).first.flatMap { Double($0) } ?? 0.0
        let steps: Int = 20
        let duration = 0.350
        let rate = duration / Double(steps)
        let diff = upto - from
        for i in 0...steps {
            DispatchQueue.main.asyncAfter(deadline: .now() + rate * Double(i)) {
                self.text = "\(from + diff * (Double(i) / Double(steps)))"
            }
        }
    }
}
Sergio
  • 2,346
  • 2
  • 24
  • 28