暗色模式下Shape颜色不符合预期,如何实现颜色随模式切换?
问题分析与解决方案
嘿,我来帮你排查这个问题~你遇到的核心问题是动态颜色没有随着暗黑模式切换自动更新,原因很简单:你在ShapeView的初始化方法里一次性设置了shapeLayer.strokeColor = UIColor.label.cgColor,但UIColor.label是动态颜色,它的实际值依赖于当前的traitCollection(包含系统颜色模式),而CAShapeLayer不会自动监听模式变化来刷新颜色。
解决方法一:利用SwiftUI环境触发更新(更贴合SwiftUI生态)
既然你用了UIViewRepresentable来包装UIKit视图,那可以直接借助SwiftUI的@Environment获取当前颜色模式,在updateUIView方法里更新strokeColor——因为当系统颜色模式变化时,SwiftUI会自动调用updateUIView方法:
@available(iOS 13.0, *) struct ShapeWrapper: UIViewRepresentable { // 订阅当前环境的颜色模式 @Environment(\.colorScheme) var colorScheme func makeUIView(context: UIViewRepresentableContext<ShapeWrapper>) -> ShapeView { ShapeView() } func updateUIView(_ uiView: ShapeView, context: UIViewRepresentableContext<ShapeWrapper>) { // 根据当前颜色模式设置对应颜色 // 方式1:直接指定黑白 uiView.shapeLayer.strokeColor = colorScheme == .dark ? UIColor.white.cgColor : UIColor.black.cgColor // 方式2:继续使用UIColor.label,获取当前模式下的实际颜色值 // uiView.shapeLayer.strokeColor = UIColor.label.resolvedColor(with: uiView.traitCollection).cgColor } }
解决方法二:在UIKit视图内部监听模式变化
如果你希望完全在UIKit层面处理颜色更新,可以让ShapeView监听系统颜色变化的通知,并重写traitCollectionDidChange方法,确保在模式切换或设备旋转时更新颜色:
class ShapeView : UIView { let shapeLayer = CAShapeLayer() init() { super.init(frame: CGRect.zero) setupShape() // 监听系统颜色变化通知 NotificationCenter.default.addObserver( self, selector: #selector(updateStrokeColor), name: UIColor.systemColorsDidChangeNotification, object: nil ) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { // 移除通知,避免内存泄漏 NotificationCenter.default.removeObserver(self) } private func setupShape() { shapeLayer.path = UIBezierPath( arcCenter: CGPoint(x: 0, y: 0), radius: 100, startAngle: 0, endAngle: CGFloat(Double.pi), clockwise: true ).cgPath updateStrokeColor() // 初始化时设置初始颜色 layer.addSublayer(shapeLayer) } @objc private func updateStrokeColor() { // 获取当前traitCollection下的动态颜色实际值 shapeLayer.strokeColor = UIColor.label.resolvedColor(with: traitCollection).cgColor } // 当traitCollection(包含颜色模式)变化时,主动更新颜色 override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) updateStrokeColor() } }
为什么原来的代码不生效?
UIColor.label这类动态颜色,本身包含了不同模式下的颜色值,但直接调用.cgColor时,只会返回当前时刻对应traitCollection的颜色值。你在ShapeView初始化时设置一次后,CAShapeLayer不会自动追踪traitCollection的变化,所以模式切换后颜色不会更新,必须手动触发颜色刷新操作。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

