You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 5+中如何在UIView扩展中根据UserInterfaceStyle切换UIColor

如何在UIView扩展中根据UIUserInterfaceStyle切换UIColor?

在UIViewController中,我们可以通过重写traitCollectionDidChange方法监听界面风格(深色/浅色模式)变化,进而调整UI颜色:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        self.changeUIWithUserInterface(style: self.traitCollection.userInterfaceStyle)
    }
}

但UIView的扩展无法直接重写traitCollectionDidChange方法,以下是两种可行的解决方案:

方案1:通过协议扩展+方法交换实现通用监听逻辑

定义一个协议声明颜色更新方法,为UIView提供协议默认实现,同时通过方法交换让所有UIView实例自动监听风格变化:

protocol DynamicColorCapable: UIView {
    func updateColors(for style: UIUserInterfaceStyle)
}

extension DynamicColorCapable {
    func setupTraitChangeListener() {
        // 监听屏幕trait变化通知
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleTraitChange),
            name: UIScreen.traitCollectionDidChangeNotification,
            object: nil
        )
        // 初始化时先设置一次对应风格的颜色
        updateColors(for: traitCollection.userInterfaceStyle)
    }
    
    @objc private func handleTraitChange() {
        DispatchQueue.main.async {
            self.updateColors(for: self.traitCollection.userInterfaceStyle)
        }
    }
}

extension UIView: DynamicColorCapable {
    func updateColors(for style: UIUserInterfaceStyle) {
        // 这里根据风格自定义颜色逻辑,示例:
        backgroundColor = style == .dark ? .black : .white
        textColor = style == .dark ? .white : .black
    }
    
    @objc private func commonInit() {
        setupTraitChangeListener()
    }
    
    static func swizzleInitMethods() {
        let originalInit = #selector(UIView.init(frame:))
        let swizzledInit = #selector(commonInit)
        
        guard let originalMethod = class_getInstanceMethod(self, originalInit),
              let swizzledMethod = class_getInstanceMethod(self, swizzledInit) else { return }
        
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
}

// 在App启动时触发方法交换
extension UIApplication {
    static func enableDynamicColorSupport() {
        UIView.swizzleInitMethods()
    }
}

// 在AppDelegate的didFinishLaunchingWithOptions中调用:
// UIApplication.enableDynamicColorSupport()

方案2:使用UIColor动态初始化器(更简洁)

如果仅需为UI元素设置随风格变化的颜色,可直接使用UIColor的动态构造方法,系统会自动处理风格切换:

extension UIColor {
    static var dynamicBackground: UIColor {
        if #available(iOS 13.0, *) {
            return UIColor { traitCollection in
                traitCollection.userInterfaceStyle == .dark ? .black : .white
            }
        } else {
            return .white // 兼容iOS13以下版本
        }
    }
    
    static var dynamicText: UIColor {
        if #available(iOS 13.0, *) {
            return UIColor { traitCollection in
                traitCollection.userInterfaceStyle == .dark ? .white : .black
            }
        } else {
            return .black
        }
    }
}

// 在UIView扩展中直接使用动态颜色
extension UIView {
    func setupDynamicAppearance() {
        backgroundColor = .dynamicBackground
        if let label = self as? UILabel {
            label.textColor = .dynamicText
        }
    }
}

内容的提问来源于stack exchange,提问作者Nayan Dave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:25:17