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

iOS切换明暗模式后GradientView渐变颜色不更新的修复咨询

问题:切换深色/浅色模式后GradientView渐变颜色不更新

当App处于深色/浅色模式时,将App退到后台,在手机设置中切换模式后返回App,自定义的GradientView不会重新绘制渐变颜色。虽然traitCollectionDidChange触发了updateColors方法,但渐变颜色没有发生变化。使用的自定义动态颜色本身适配正常,问题仅出在GradientView上。

原代码实现

GradientView代码

final class GradientView: UIView {
    
    var locations: [NSNumber]? = [0.0, 1.0] {
        didSet { updateLocations() }
    }
    
    var colors: [CGColor]? = [Color.backgroundPrimary.withAlphaComponent(0).cgColor, Color.backgroundPrimary.cgColor] {
        didSet { updateColors() }
    }
    
    var gradientLayer: CAGradientLayer { layer as! CAGradientLayer }
    
    override public class var layerClass: AnyClass { CAGradientLayer.self }
    
    convenience init(_ from: CGColor, _ to: CGColor) {
        self.init(frame: .zero)
        colors = [from, to]
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        updateLocations()
        updateColors()
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        if #available(iOS 13.0, *) {
            if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
                self.updateColors()
            }
        }
    }
}

private extension GradientView {
    
    func updateLocations() {
        gradientLayer.locations = self.locations
    }
    
    func updateColors() {
        gradientLayer.colors = self.colors
    }
}

自定义动态颜色代码

public static var backgroundPrimary = dynamicColor(light:  colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1), dark:  colorLiteral(red: 0.0, green: 0.0, blue: 0.0, alpha: 1))

问题原因

核心问题在于colors属性存储的是静态的CGColor值:

  • 初始化时,Color.backgroundPrimary.cgColor会根据当前模式生成对应的CGColor并存储。
  • 当系统模式切换后,动态UIColorColor.backgroundPrimary会更新,但之前存储的CGColor不会自动同步变化。
  • 调用updateColors时,只是把旧的CGColor重新赋值给渐变层,所以颜色不会更新。

修复方案

修复后的代码

final class GradientView: UIView {
    
    var locations: [NSNumber]? = [0.0, 1.0] {
        didSet { updateLocations() }
    }
    
    // 将属性类型改为UIColor,保留动态颜色的适配能力
    var colors: [UIColor]? = [Color.backgroundPrimary.withAlphaComponent(0), Color.backgroundPrimary] {
        didSet { updateColors() }
    }
    
    var gradientLayer: CAGradientLayer { layer as! CAGradientLayer }
    
    override public class var layerClass: AnyClass { CAGradientLayer.self }
    
    // 调整初始化器参数为UIColor
    convenience init(_ from: UIColor, _ to: UIColor) {
        self.init(frame: .zero)
        colors = [from, to]
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        updateLocations()
        updateColors()
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        if #available(iOS 13.0, *) {
            if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
                updateColors()
            }
        }
    }
}

private extension GradientView {
    
    func updateLocations() {
        gradientLayer.locations = self.locations
    }
    
    func updateColors() {
        // 每次更新时,根据当前traitCollection获取对应模式的CGColor
        gradientLayer.colors = colors?.map { color in
            if #available(iOS 13.0, *) {
                return color.resolvedColor(with: traitCollection).cgColor
            } else {
                return color.cgColor
            }
        }
    }
}

关键修复点

  1. 存储UIColor而非CGColor:保留动态颜色的特性,确保模式切换时能获取到对应颜色值。
  2. 动态获取当前模式的CGColor:在updateColors中,通过resolvedColor(with: traitCollection)方法获取当前模式下的UIColor,再转换为CGColor赋值给渐变层,保证每次更新都是最新的颜色。
  3. 适配初始化逻辑:调整便利初始化器的参数类型为UIColor,保持接口一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 10:37:39