Reputation: 4340
I have a UIStepper value binded to a UILabel text:
unitsStepper.rx.value.asObservable()
.map { Int($0).description }
.bind(to: stepperCountLabel.rx.text)
.disposed(by: rx.disposeBag)
And i would like to animate the label every time it changes, theres a better way to that instead of this?
unitsStepper.rx.value.asObservable()
.map { Int($0).description }.subscribe(onNext: { [weak self] value in
guard let strongSelf = self else { return }
UIView.animate(withDuration: 0.4, animations: {
strongSelf.stepperCountLabel.text = value
strongSelf.stepperCountLabel.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}, completion: { completed in
strongSelf.stepperCountLabel.transform = CGAffineTransform.identity
})
}).disposed(by: rx.disposeBag)
Upvotes: 1
Views: 1939
Reputation: 9039
Personally, I don't think there is anything wrong with that. If you wanted it to be more readable, less nested, then you can break it out a bit. Your needs will vary, and you don't want to pollute something general with something very specific, but it looks like you have something repetitive, a sort of pulsate.
I needed something like that for form validation, and wrote this (your actual animation is simpler though, I think I started with a multi-part key frame animation but reduced it to just back and forth)
extension UIView {
func shake(totalDuration: TimeInterval, totalCycles: Int = 1) {
let animationDuration = totalDuration / Double(totalCycles)
let wiggle = CAKeyframeAnimation(keyPath: "transform.rotation.z")
wiggle.values = [0.0, -0.04, 0.04, 0.0]
wiggle.duration = animationDuration
wiggle.repeatCount = Float(totalCycles)
layer.add(wiggle, forKey: "wiggle")
let vertical = CAKeyframeAnimation(keyPath: "transform.translation.y")
vertical.values = [0.0, -2.0, 2.0, 0]
vertical.duration = animationDuration
vertical.repeatCount = Float(totalCycles)
layer.add(vertical, forKey: "vertical")
let horizontal = CAKeyframeAnimation(keyPath: "transform.translation.x")
horizontal.values = [0.0, 2.0, -2.0, 0]
horizontal.duration = animationDuration
horizontal.repeatCount = Float(totalCycles)
layer.add(horizontal, forKey: "horizontal")
}
func pulse(totalDuration: TimeInterval, ratio: CGFloat = 1.2) {
UIView.animateKeyframes(
withDuration: totalDuration,
delay: 0,
options: [],
animations: {
UIView.addKeyframe(
withRelativeStartTime: 0,
relativeDuration: 0.5,
animations: { [unowned self] in
self.transform = .init(scaleX: ratio, y: ratio)
})
UIView.addKeyframe(
withRelativeStartTime: 0.5,
relativeDuration: 0.5,
animations: { [unowned self] in
self.transform = .identity
})
}, completion: { completed in })
}
}
I then wrote a simple validator struct with a condition and action closure, and would zip through a list of them upon form changes / validation.
But back to your question, your animation itself is minimal, if it was a one-off, you could put it on the enclosing class, if it was general, you could add it as an extension, but as a one-off, it's still fine as it is (if I were reading the code)
Upvotes: 0