• Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

The animate method of UIView only performs Frame, alpha, color, and transform operations on a UIView. So you can’t do all of these with UIView animate. Here’s what you need — CADisplaylink, a timer object that allows your app to synchronize its drawing based on the screen refresh rate.

1. Establish CADisplaylink

Start by creating a Label.

 let countingLabel: UILabel = {
        let label = UILabel()
        label.text = "1234"
         label.textAlignment = .center
        label.font = UIFont.boldSystemFont(ofSize: 18)
        return label
    }()
Copy the code

Add it to the subview and give it a frame.

 view.addSubview(countingLabel)
 countingLabel.frame = view.frame
Copy the code

Then create a CADisplayLink and add it to the main thread runloop.

  let displayLink =  CADisplayLink(target: self, selector: #selector(handleUpdate))
  displayLink.add(to: .main, forMode: .default)
Copy the code

2. Start and end values

Create start and end values

Var startValue = 0.0 let endValue = 1200.0Copy the code

So if I go ahead and do a little bit of code inside the displayLink response method and I run it, I can see that the number inside the Label is bouncing.

  @objc func handleUpdate() {
        self.countingLabel.text = "\(startValue)"
        startValue += 1
           if startValue > endValue {
            startValue = endValue
        }
    }
Copy the code

3. Animation duration

Gets the current time and sets the desired duration

Let animationDuration = 1.5 let animationStartDate = Date()Copy the code

Then modify the handleUpdate method to change the value of the UILabel based on the past time and the set animation duration.

 @objc func handleUpdate() {
      let now = Date()
        let elapsedTime = now.timeIntervalSince(animationStartDate)
        if elapsedTime > animationDuration {
            self.countingLabel.text = "\(endValue)"

        } else {
        let percentage = elapsedTime / animationDuration
        let value = startValue + percentage * (endValue - startValue)
        self.countingLabel.text = "\(value)"
        }
        }
Copy the code

There are two more problems here, one is the removal of displayLink, and one is the decimal point after the value. To remove displayLink the problem is to move displayLink outside as a VC property and then remove it after the animation. And to solve the decimal problem, you just convert it to an Int. Final code:

import UIKit class ViewController: UIViewController { let countingLabel: UILabel = { let label = UILabel() label.text = "1234" label.textAlignment = .center label.font = UIFont.boldSystemFont(ofSize: 18) return label }() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. view.addSubview(countingLabel) countingLabel.frame = view.frame displayLink = CADisplayLink(target: self, selector: #selector(handleUpdate)) displayLink?.add(to: .main, forMode: .default)} var startValue = 0.0 let endValue = 1200.0 var displayLink: CADisplayLink? Let animationDuration = 1.5 let animationStartDate = Date() @objc func handleUpdate() {let now = Date() let elapsedTime = now.timeIntervalSince(animationStartDate) if elapsedTime > animationDuration { self.countingLabel.text  = "\(Int(endValue))" displayLink?.invalidate() displayLink = nil } else { let percentage = elapsedTime / animationDuration let value = startValue + percentage * (endValue - startValue) self.countingLabel.text = "\(Int(value))" } } }Copy the code