[SWIFT] Cách tạo Counting Label Animation
Môi trường phát triển: Swift Language Version: Swift 5.0 Xcode: Version 10.2.1 (10E1001) Deployment Target: 12.0 Bước 1: Khởi tạo các thuộc tính của Counting Label Ta khởi tạo các thuộc tính sau trong class CountingLabel : class CountingLabel: UILabel { private let ...
Môi trường phát triển:
- Swift Language Version: Swift 5.0
- Xcode: Version 10.2.1 (10E1001)
- Deployment Target: 12.0
Bước 1: Khởi tạo các thuộc tính của Counting Label
Ta khởi tạo các thuộc tính sau trong class CountingLabel:
class CountingLabel: UILabel { private let counterExponent: Float = 3.0 enum CounterAnimationType { case Linear case EaseIn case EaseOut } enum CounterType { case Int case Float } private var startNumber: Float = 0.0 private var endNumber: Float = 0.0 private var progress: TimeInterval! private var duration: TimeInterval! private var lastUpdate: TimeInterval! private var timer: Timer? private var counterType: CounterType! private var counterAnimationType: CounterAnimationType!
Trong đó:
- counterExponent: số mũ để tính counter.
- startNumber: giá trị bắt đầu.
- endNumber: giá trị kết thúc.
- progress: khoảng thời gian tiến độ.
- duration: khoảng thời hạn.
- lastUpdate: thời điểm cập nhật cuối.
- timer: bộ đếm thời gian kích hoạt sau một khoảng thời gian nhất định.
- counterType: kiểu giá trị counter.
- counterAnimationType: kiểu hiệu ứng counter.
Bước 2: Setup timer
Tiếp theo, ta khởi tạo hàm count() để setup giá trị cho các thuộc tính của class CountingLabel và setup timer.
func count(fromValue: Float, to toValue: Float, withDuration duration: TimeInterval, andAnimationType animationType: CounterAnimationType, andCounterType counterType: CounterType) { self.startNumber = fromValue self.endNumber = toValue self.duration = duration self.counterType = counterType self.counterAnimationType = animationType self.progress = 0 self.lastUpdate = Date.timeIntervalSinceReferenceDate invalidateTimer() // Reset timer if duration == 0 { {1} // Update text for label return } // Setup timer timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(updateValue), userInfo: nil, repeats: true) }
Hàm updateValue() cập nhật giá trị của progress, lastUpdate và text của Counting Label.
@objc private func updateValue() { let now = Date.timeIntervalSinceReferenceDate progress = progress + (now - lastUpdate) // calculate a progress lastUpdate = now if progress >= duration { invalidateTimer() // Reset timer progress = duration } {2} // UpdateText in Label }
Hàm invalidateTimer() dừng timer khỏi chạy một lần nữa và yêu cầu loại bỏ nó khỏi vòng lặp chạy của nó.
private func invalidateTimer() { timer?.invalidate() timer = nil }
Bước 3: Setup hàm updateText() và updateCounter()
Hàm updateText() cập nhật giá trị text của label.
private func updateText(_ value: Float) { switch counterType! { case .Int: self.text = "(Int(value))" case .Float: self.text = String(format: "%.2f", value) } }
Hàm updateCounter() trả về giá trị counter tại mỗi thời điểm khác nhau.
private func updateCounter(counterValue: Float) -> Float { switch counterAnimationType! { case .Linear: return counterValue case .EaseIn: return powf(counterValue, counterExponent) // exponent method for float case .EaseOut: return 1.0 - powf(1.0 - counterValue, counterExponent) } }
Biến currentCounterValue là giá trị hiện tại của counter.
private var currentCounterValue: Float { if progress >= duration { return endNumber } let percentage = Float(progress/duration) let update = updateCounter(counterValue: percentage) return startNumber + (update * (endNumber - startNumber)) }
Tiếp theo ta thay thế {1} bằng đoạn code sau:
updateText(toValue)
và {2} bằng đoạn code sau:
updateText(currentCounterValue)
Bước 4: Add Counting Label Animation
final class ViewController: UIViewController { @IBOutlet private weak var countingLabel: CountingLabel! override func viewDidLoad() { super.viewDidLoad() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) countingLabel.count(fromValue: 0, to: 9999, withDuration: 10, andAnimationType: .EaseOut, andCounterType: .Int) } }
Và đây là kết quả: