How to animate incrementing number in UILabel

39,295

Solution 1

You could use a flag to see if it has to go up or down. Instead of a for loop, use a while loop. In this way, you are creating a loop that keeps going, so you have to find a way to stop it also, f.e. by a button press.

Solution 2

I actually made such a class just for this called UICountingLabel:

http://github.com/dataxpress/UICountingLabel

It allows you to specify whether you want the counting mode to be linear, ease in, ease out, or ease in/out. Ease in/out starts counting slowly, speeds up, and then finishes slowly - all in whatever amount of time you specify.

It doesn't currently support setting the actual font size of the label based on the current value, though I may add support for that if it's a feature that's in-demand. Most of the labels in my layouts don't have a lot of room to grow or shrink, so I'm not sure how you want to use it. However, it behaves totally like a normal label, so you can change the font size on your own as well.

Solution 3

You can use GCD to shift delays to background threads.

Here is the example of value animation (from 1 to 100 in 10 seconds)

float animationPeriod = 10;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    for (int i = 1; i < 101; i ++) {
        usleep(animationPeriod/100 * 1000000); // sleep in microseconds
        dispatch_async(dispatch_get_main_queue(), ^{
            yourLabel.text = [NSString stringWithFormat:@"%d", i];
        });
    }
});

Solution 4

Here @malex's answer in swift 3.

func incrementLabel(to endValue: Int) {
    let duration: Double = 2.0 //seconds
    DispatchQueue.global().async {
        for i in 0 ..< (endValue + 1) {
            let sleepTime = UInt32(duration/Double(endValue) * 1000000.0)
            usleep(sleepTime)
            DispatchQueue.main.async {
                self.myLabel.text = "\(i)"
            }
        }
    }
}

However, I strongly recommend simply downloading this class from GitHub and dragging it into your project, I've resorted to using it because the timing in my code doesn't seem to adjust properly for lower/higher count numbers. This class works great and looks very good. See this medium article for reference.

Solution 5

There you have it without blocking sleeps! stick this to a UILabel and it counts up and down from the value currently displaying, cleaning non numbers first. Adjust from Double to Int or Float if needed.

yourlabel.countAnimation(upto: 100.0)
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)))"
            }
        }
    }
}
Share:
39,295

Related videos on Youtube

Darren
Author by

Darren

Updated on July 09, 2022

Comments

  • Darren
    Darren almost 2 years

    I have a label showing a number and I want to change it to a higher number, however I'd like to add a bit of flare to it. I'd like to have the number increment up to the higher number with an ease inout curve so it speeds up then slows down. This answer shows how to make it increment (the 2nd answer, not the accepted answer) but I'd rather animate it so I could also make it increase in size slightly then shrink again as well as the ease inout curve. how to do a running score animation in iphone sdk

    Any ideas how best to achieve this? Thanks

    The start/end numbers will be user inputted and I want it to increment up the the end number in the same amount of time. So if I have start 10 end 100 or start 10 end 1000 I want it to count up to the end number in say 5 seconds.

  • Darren
    Darren over 12 years
    Maybe I didn't explain myself enough. I have added more to my question. I can increment from 1 number to another using a for loop or a while loop. However I want it to count up by slowly speeding up then slowing down towards the end. And all to happen in a set amount of time.
  • Maarten Kesselaers
    Maarten Kesselaers over 12 years
    Then you can use 2 for-loops : - One to go up - And one to count down If you want to use a set amount of time, you'll have to use a timers, because otherwise, it happens as fast as the cpu can process it.
  • Darren
    Darren over 12 years
    I don't need to count down. I can manage the loops, I just need to make the process happen in a certain amount of time. Can I put the count up loop in a timer to make the process happen in that amount of time, like with an animation? I thought timers would just tell it how often to happen.
  • Maarten Kesselaers
    Maarten Kesselaers over 12 years
    If you see the first answer off the link you posted in your question, you can see that the timer will do the loop 15 times a second. You could use two loops with a different time. Another way is using the option sleep(milliseconds) in your loop. If you use a parameter for the wait time, you can decrease it via a custom algorithm. f.e. first time it runs 2000 ms, second time 2000ms - (i * 100ms), etc.
  • Darren
    Darren over 12 years
    The problem with that is if I get a high number I have to count to. I wouldn't want to slow it down, i'd want to speed it up.
  • Maarten Kesselaers
    Maarten Kesselaers over 12 years
    Then you use the reverse off what I said : Take a start time of for example 1000ms 2nd time : 1000ms + i * 100 ms
  • Tim
    Tim about 11 years
    Glad you like it :) If you have any feature requests feel free to post 'em on Github!
  • user3344977
    user3344977 over 9 years
    When I pasted this into Xcode, I got an error over "MAIN_QUEUE". I had to replace "MAIN_QUEUE" with "dispatch_get_main_queue()". Otherwise, this a great answer.
  • user3344977
    user3344977 over 9 years
    Well thank you for posting it. The heavily upvoted UICountingLabel answer above is not working correctly anymore so this was a nice alternative.
  • PaperThick
    PaperThick about 9 years
    This is a nice one but does anyone know how to get UICountingLabel to work with comma as a decimal point instead on period?
  • Simon
    Simon almost 9 years
    I downloaded and tested a count from 0 to 30 in 3 seconds but did not work. The animation lasted closer to 4 seconds.
  • Reshad
    Reshad over 8 years
    this gives me the value straight away.. without "animating" in swift 2.0 any idea why?
  • El Tomato
    El Tomato over 7 years
    I don't think that's correct. I think sleepTime is misconfigured.
  • Travis M.
    Travis M. over 7 years
    Great catch. I corrected the answer to include the duration calculation, however, in my testing, the math is correct but there's a delay in the sleep/dispatch.main process so for the code above, it takes around 4 seconds to complete instead of 2 as entered.
  • Derek Saunders
    Derek Saunders almost 5 years
    I implemented this into my own project, and it works perfectly.
  • Darren
    Darren about 4 years
    This question is 8 years old
  • Sergio
    Sergio about 4 years
    Simpler solution.
  • Lal Krishna
    Lal Krishna almost 4 years
    That gist code seems to be dead. Please update the answer. @TravisM.
  • Junaid
    Junaid over 2 years
    Is there a swift version of this?