Swift 4 - setNeedsDisplay 和 layoutIfNeeded 不在 self.UIView 上重绘 UILabel

Swift 4 - setNeedsDisplay and layoutIfNeeded not redrawing UILabel on self.UIView

基本上,我有一个自定义 UILabel subclass,它根据变量设置标签颜色。

class MyLabel: UILabel {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        textColor = GlobalVars.mainTextColor
    }
}

在我的视图控制器上,我有一个设置白色背景并将文本颜色变量设置为黑色的按钮:

@IBAction func btnWhite(_ sender: UIButton) {
        GlobalVars.mainTextColor = UIColor.black
        GlobalVars.bgColor = UIColor.white
        self.view.backgroundColor = UIColor.white
        self.view.setNeedsDisplay()
        self.view.layoutIfNeeded()
        DispatchQueue.main.async { [weak self] in
            self?.view.setNeedsLayout()
            self?.view.layoutIfNeeded()
        }
    }

单击它并更新变量后,我希望 ViewController 重绘标签,这将更新它们的文本颜色。如果我弹出 VC 并返回,这个工作正常,但我希望显示在单击按钮时更新。我在视图上有一堆标签,它们都设置为 myLabel class。我不想手动更改屏幕上每个标签的代码,我只想重新绘制它。 UIView 不是自定义的 class,只是 View Controller 附带的默认 UIView。这应该已经在主线程上发生了,但我已经尝试添加 dispatch.main.async 以防万一。我希望它最终不需要两者。 Image of my view controller layout here

当我点击按钮时,背景变为白色,但标签文本颜色没有更新,我相信这是因为它没有重绘它们。还有第二个按钮 btnBlack,可以将其切换为 light/dark 模式效果的相反方向。

想法?

您必须更改按钮单击方法中的 TextColor

@IBAction func btnWhite(_ sender: UIButton) {
     myCustomLabel.textColor = UIColor.blue
} 

并且不需要调用下面提到的方法

self.view.setNeedsDisplay()
self.view.layoutIfNeeded()

注意:没有其他方法可以更改 UIlabel TextColor

每当 GlobalVars.mainTextColorGlobalVars.bgColor 值发生变化时,您必须重新设置所有标签的颜色。

一种选择是使用通知。您可以 post 关于 didSet 全局变量的通知,并在 MyLabel class 中捕获通知并更新颜色。

class GlobalVars {
    static let onChangeColorNotification = "onChangeColorNotification"
    static var mainTextColor:UIColor? {
        didSet {
            NotificationCenter.default.post(Notification.init(name: Notification.Name(rawValue: onChangeColorNotification)))
        }
    }
}

并且在你的 MyLabel class

class MyLabel: UILabel {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        onChangeGlogabColor()
        NotificationCenter.default.addObserver(self, selector: #selector(onChangeGlogabColor), name: NSNotification.Name(rawValue: GlobalVars.onChangeColorNotification), object: nil)
    }
    @objc func onChangeGlogabColor() {
        textColor = GlobalVars.mainTextColor
    }
}

您可以对所有自定义 class 执行相同的操作,例如 MyButtonMyView,捕捉通知并更新颜色。

而且您不必调用 setNeedsDisplay()layoutIfNeeded()

@IBAction func btnWhite(_ sender: UIButton) {
    GlobalVars.mainTextColor = UIColor.black
    GlobalVars.bgColor = UIColor.white
    self.view.backgroundColor = UIColor.white        
}

Bilal 的回答是正确的。有时需要一种完全不同的方法。感谢新鲜的眼睛,这是最终代码。

添加下面的代码并将所有标签设置为此 "MyLabel" class。然后只要 GlobalVars.mainTextColor 变量发生变化,标签就会更新它们的文本颜色。这可以适用于 UIButtons 或任何 属性 您需要在 var 更改时更新的内容。这会在加载的任何 VC 上更新任何带有此 class 的标签。这也解决了我的根 VC 标签也需要更新的问题,因为它们也已经用原始颜色绘制,非常光滑!

class MyLabel: UILabel {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        textColor = GlobalVars.mainTextColor
        NotificationCenter.default.addObserver(self, selector: #selector(onChangeGlobalColor), name: NSNotification.Name(rawValue: "onChangeColorNotification"), object: nil)
    }
    @objc func onChangeGlobalColor() {
        textColor = GlobalVars.mainTextColor
    }
}

struct GlobalVars {
    static var mainTextColor:UIColor = UIColor() {
        didSet {
            NotificationCenter.default.post(Notification.init(name: Notification.Name(rawValue: "onChangeColorNotification")))
        }
    }

@IBAction func btnWhite(_ sender: UIButton) {
        GlobalVars.mainTextColor = UIColor.black
        self.view.backgroundColor = UIColor.white
    }
@IBAction func btnBlack(_ sender: UIButton) {
        GlobalVars.mainTextColor = UIColor.white
        self.view.backgroundColor = UIColor.black
    }