Often in swift, I may want to have a property that, when set generally animates. In other words
class SelectableView: UIView {
var isSelected: Bool = false {
willSet {
UIView.animate(withDuration: 0.200) {
self.backgroundColor = .red
}
}
}
}
However, I am realizing that it may not be the best practice. For example, when I use my class elsewhere, I may accidentally do something like:
let k = SelectableView()
UIView.animate(withDuration: 0.500) {
k.isSelected = true
k.alpha = 1.0
k.backgroundColor = .red // notice this!
}
In that event, what even occurs? What exactly is the behavior there? Does the color go to red in 500 milliseconds or 200 milliseconds? Does willSet
matter versus didSet
? What happens if I straight up nested the UIView.animate
inline rather in the setter?
In general, is it perhaps a bad practice to have an animation block in the setter?
In the setter you can check the value of UIView.inheritedAnimationDuration
. If it’s 0, use default duration (i.e. 0.2). If it’s >0, use that value. Also, alternatively, if inherited duration is >0, you can skip animation in the setter, and just directly assign the value.
class SelectableView: UIView {
var isSelected: Bool = false {
didSet {
let duration = UIView.inheritedAnimationDuration
UIView.animate(withDuration: duration > 0 ? duration : 0.200) {
self.backgroundColor = .red
}
}
}
}
In terms of good practices, Apple uses two setters in such cases:
isSelected
- no implicit animationsetSelected(_ selected: Bool, animated: Bool)
- opted-in animationThe first one can be dynamic and call the second one with animated: false
argument.