简体   繁体   中英

How to set gradient color to view in Dark mode ios?

I want to change the gradient color in dark mode. But it not changing. Gradient set once the view is setup. Color not changing while switching between light and dark mode.

 if let layer = layer as? CAGradientLayer {
        if let startGradientColor = startGradientColor, let endGradientColor = endGradientColor {
            layer.colors = [startGradientColor.cgColor, endGradientColor.cgColor]
        } else {
            layer.colors = gradientColors.map {$0.cgColor}
        }
        layer.startPoint = CGPoint(x: 0, y: 0)  // top
        layer.endPoint = CGPoint(x: 1, y: 1)    // bottom
    }

You need to make your app react to changes to the trait collection, something like this:

extension YourViewController {
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if #available(iOS 13.0, *) {
            guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else {
                return
            }

            // redraw your layers here
        }
    }
}

You can do this with "Dynamic Providers"

For example, in your custom gradient view class:

var startGradientColorDarkMode: UIColor = .white
var startGradientColorLightMode: UIColor = .black

lazy var myStartColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in
    if traitCollection.userInterfaceStyle == .dark {
        return self.startGradientColorDarkMode
    } else {
        return self.startGradientColorLightMode
    }
}

You can then use myStartColor.cgColor in your gradient colors array.

Here is a complete example:

class MyGradientView: UIView {

    // default Dark mode - white to orange
    var startGradientColorDarkMode: UIColor = .white
    {
        didSet {
            self.setNeedsLayout()
        }
    }
    var endGradientColorDarkMode: UIColor = .orange
    {
        didSet {
            self.setNeedsLayout()
        }
    }

    // default Light mode - black to blue
    var startGradientColorLightMode: UIColor = .black
    {
        didSet {
            self.setNeedsLayout()
        }
    }
    var endGradientColorLightMode: UIColor = .blue
    {
        didSet {
            self.setNeedsLayout()
        }
    }

    lazy var myStartColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in
        if traitCollection.userInterfaceStyle == .dark {
            return self.startGradientColorDarkMode
        } else {
            return self.startGradientColorLightMode
        }
    }

    lazy var myEndColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in
        if traitCollection.userInterfaceStyle == .dark {
            return self.endGradientColorDarkMode
        } else {
            return self.endGradientColorLightMode
        }
    }

    private var gradientLayer: CAGradientLayer!

    override class var layerClass: AnyClass {
        return CAGradientLayer.self
    }

    override func layoutSubviews() {
        self.gradientLayer = self.layer as? CAGradientLayer
        self.gradientLayer.colors = [myStartColor.cgColor, myEndColor.cgColor]

        self.gradientLayer.startPoint = CGPoint(x: 0, y: 0)  // top
        self.gradientLayer.endPoint = CGPoint(x: 1, y: 1)    // bottom
    }

}

class GradientTestViewController: UIViewController {

    let testView = MyGradientView(frame: CGRect(x: 40, y: 100, width: 240, height: 240))

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(testView)

        let tapGR = UITapGestureRecognizer(target: self, action: #selector(didTap))
        self.view.addGestureRecognizer(tapGR)

        // just for example
        // change colors from our defaults

        // change dark mode to red-to-yellow
        testView.startGradientColorDarkMode = .red
        testView.endGradientColorDarkMode = .yellow
        // change light mode to darkbown-to-lightBrown
        testView.startGradientColorLightMode = UIColor(red: 0.45, green: 0.3, blue: 0.25, alpha: 1.0)
        testView.endGradientColorLightMode = UIColor(red: 0.8, green: 0.65, blue: 0.3, alpha: 1.0)

    }

    @objc func didTap(tapGR: UITapGestureRecognizer) {
        // we can change the gradient colors on-the-fly
        if testView.startGradientColorDarkMode == UIColor.red {
            // change dark mode to blue-to-cyan
            testView.startGradientColorDarkMode = .blue
            testView.endGradientColorDarkMode = .cyan
            // change light mode to darkGreen-to-lightGreen
            testView.startGradientColorLightMode = UIColor(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0)
            testView.endGradientColorLightMode = .green
        } else {
            // change dark mode to red-to-yellow
            testView.startGradientColorDarkMode = .red
            testView.endGradientColorDarkMode = .yellow
            // change light mode to darkbown-to-lightBrown
            testView.startGradientColorLightMode = UIColor(red: 0.45, green: 0.3, blue: 0.25, alpha: 1.0)
            testView.endGradientColorLightMode = UIColor(red: 0.8, green: 0.65, blue: 0.3, alpha: 1.0)
        }
    }

}

This is what I did, works great.

SomeGradientView.swift

class SomeGradientView: UIView {

    override open class var layerClass: AnyClass { return GradientLayer.self }

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        if #available(iOS 13.0, *) {
            if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
                (layer as? GradientLayer)?.resetGradientColors()
                setNeedsDisplay()
            }
        }
    }
}

GradientLayer.swift

class GradientLayer: CAGradientLayer {

    // MARK: - Lifecycle
    override init() {
        super.init()
        setup()
    }

    override init(layer: Any) {
        super.init(layer: layer)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    // MARK: - Private
    private func setup() {
        // gradient setup
        resetGradientColors()
        locations = ...
        opacity = 1
    }

    // MARK: - Internal
    /// Used for trait collection color appearance changes
    func resetGradientColors() {
        colors = [UIColor.systemRed, UIColor.systemBlue]
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM