У меня есть пользовательский UIButton с рамкой. Я бы хотел, чтобы layer.borderColor
синхронизировался с titleLabel
, когда кнопка реагирует на пользовательские события - то есть становится выделенным или выбранным .
Иногда эти события анимируются с задержкой, иногда сразу.
т.д .:
Нажмите и удерживайте кнопку - немедленно
Отпустите кнопку - с анимацией
Как заставить границу кнопки повторять то же поведение? Как отследить переходы между UIControlStates ?
т.е. Решение о том, нужно ли анимировать границу, зависит от перехода:
Normal
-> Highlighted
- без анимации
Highlighted
-> Normal
- с анимацией
Как я могу обнаружить такие переходы?
Вот код для кнопки, которая не обращается к событию перемещения пальца за пределы, но в остальном работает хорошо:
import UIKit
final class BorderButton: UIButton {
override var isEnabled: Bool {
didSet {
updateBorderColor()
}
}
override var isSelected: Bool {
didSet {
updateBorderColor(animated: false)
}
}
override var isHighlighted: Bool {
didSet {
let animated = !isHighlighted
updateBorderColor(animated: animated)
}
}
override func tintColorDidChange() {
super.tintColorDidChange()
updateBorderColor()
}
private func updateBorderColor(animated: Bool = false) {
var color: UIColor = tintColor
if !isEnabled || tintAdjustmentMode == .dimmed {
color = dimmedTintColor()
} else if isHighlighted {
color = lightColor()
}
if animated {
let current = layer.borderColor ?? UIColor.clear.cgColor
let cgColor = color.cgColor
borderColorAnimation(from: current, to: cgColor, duration: 0.4)
} else {
layer.borderColor = color.cgColor
}
}
private func borderColorAnimation(from: CGColor, to: CGColor, duration: CFTimeInterval) {
let animation = CABasicAnimation(keyPath: "borderColor")
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animation.fromValue = from
animation.toValue = to
animation.duration = duration
layer.add(animation, forKey: "borderColor")
layer.borderColor = to
}
private func lightColor() -> UIColor {
var hue: CGFloat = 0, saturation: CGFloat = 0, brightness: CGFloat = 0, alpha: CGFloat = 0
tintColor.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha * 0.2)
}
private func dimmedTintColor() -> UIColor {
var hue: CGFloat = 0, brightness: CGFloat = 0, alpha: CGFloat = 0
tintColor.getHue(&hue, saturation: nil, brightness: &brightness, alpha: &alpha)
return UIColor(hue: hue, saturation: 0, brightness: brightness, alpha: alpha)
}
}