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
相关产品推荐
相关产品推荐

