我有一个带有 2 个图标和一个标签的按钮。对于 .selected 状态,该按钮具有不同的背景颜色。当我单击按钮时,会选择该按钮并推送一个新的 ViewController。我试图模仿 UITableViewCell.setSelected(animated:) 的行为,因此当用户从新的 ViewController 退出时,我希望背景颜色具有动画效果。我用这个:
UIView.transition(带有:按钮,持续时间:0.3,选项:.transitionCrossDissolve){button.isSelected = false}
当我将其放入 viewDidAppear 中时效果很好,但有点太晚了,所以我希望将其放入 viewWillAppear 中。问题是当我从 viewDidAppear 执行此操作时,按钮上的标签开始是透明的。图标精美且静态,但标签将从透明动画变为其颜色。为什么?我怎样才能防止这种情况发生?
这是一个小演示:
import UIKit
class ViewController: UIViewController {
var myButton: MyButton?
override func viewDidLoad() {
super.viewDidLoad()
myButton = MyButton()
view.addSubview(myButton!)
myButton?.frame.origin.x = 200
myButton?.frame.origin.y = 200
myButton?.addAction(.init { [weak self] _ in
self?.myButton?.isSelected = true
self?.navigationController?.pushViewController(ViewController2(), animated: true)
}, for: .touchUpInside)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIView.transition(with: myButton!, duration: 3, options: .transitionCrossDissolve) { self.myButton!.isSelected = false }
}
// override func viewDidAppear(_ animated: Bool) {
// super.viewDidAppear(animated)
// UIView.transition(with: myButton!, duration: 3, options: .transitionCrossDissolve) { self.myButton!.isSelected = false }
//
// }
}
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
}
}
class MyButton: UIButton {
let label = UILabel("Hahahaha", font: .systemFont(ofSize: 14), textColor: .black)
convenience init() {
self.init(frame: .init(x: 0, y: 0, width: 200, height: 200))
setBackgroundColor(color: .white, forState: .normal)
setBackgroundColor(color: .gray, forState: .highlighted)
setBackgroundColor(color: .gray, forState: .selected)
addSubview(label)
label.frame.origin = .init(x: 40, y: 40)
}
}
extension UIButton {
func setBackgroundColor(color: UIColor, forState: UIControl.State) {
self.clipsToBounds = true
UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
if let context = UIGraphicsGetCurrentContext() {
context.setFillColor(color.cgColor)
context.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
let colorImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.setBackgroundImage(colorImage, for: forState)
}
}
}
extension UILabel {
convenience init(_ text: String = "", font: UIFont? = nil, textColor: UIColor? = .black) {
self.init()
self.text = text
self.font = font
sizeToFit()
self.textColor = textColor
}
}
尝试从 ViewController2 退出,看到标签开始不可见。现在注释掉 viewWillAppear 并使用 viewDidAppear 代替,标签从黑色开始。
解决方案:将标签的背景颜色设置为您想要的动画起始颜色。然后从内部触发动画
viewDidAppear
。
原因: 当按下按钮并启动导航时,该按钮不再突出显示,也不再被选中。这样它就恢复到正常状态了。
现在您导航回来。称为
viewWillAppear
。它的名字暗示“视图将在稍后显示,但它还不可见”。因此,当您此时启动动画时,UIKit 会假设即使它确实对某些内容进行了动画处理,用户也看不到它。 (视图还不可见 = 该视图上的动画也不会被看到。)为了节省资源,UIKit 将忽略动画。
所以解决方案是:尽早设置背景颜色,然后在调用
viewDidAppear
时启动动画,UIKit 会实际执行它。