How to apply gradient color in view top left right bottom like this picture?

55 Views Asked by At

I want to apply view gradient color but always failed.

I want to apply gradient view like this image:

gradient view top left right bottom

I try with this code:

func gradientColor(topLeft: UIColor, bottomRight: UIColor) {
    let gradient = CAGradientLayer()
    gradient.frame = CGRect(x: 0, y: 0, width: self.mainView.bounds.width, height: self.mainView.bounds.height)
    gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
    gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
    gradient.colors = [topLeft.cgColor, bottomRight.cgColor]
    self.mainView.layer.addSublayer(gradient)
}

but result as empty no color (color did not show) at all if I called like this:

gradientColor(topLeft: UIColor.style.negativeGradient, bottomRight: UIColor.style.negative)

What is the correct code to generate gradient view like that image?

1

There are 1 best solutions below

0
DonMag On BEST ANSWER

This approach commonly fails because it is called before the views have been laid-out, so self.mainView.bounds is not valid.

A much more reliable - and flexible - approach is to subclass UIView and have it do all the "background styling" automatically.

Quick example class:

class MyCustomGradientView: UIView {

    public var gradientColor1: UIColor = .init(red: 0.887, green: 0.993, blue: 0.922, alpha: 1.0) { didSet { gradientLayer.colors = [gradientColor1.cgColor, gradientColor2.cgColor] } }
    public var gradientColor2: UIColor = .white { didSet { gradientLayer.colors = [gradientColor1.cgColor, gradientColor2.cgColor] } }
    
    public var circleColor: UIColor = .init(red: 0.904, green: 0.969, blue: 0.949, alpha: 1.0) { didSet { circleLayer.fillColor = circleColor.cgColor } }
    
    public var circleDiameter: CGFloat = 140.0 { didSet { setNeedsLayout() } }
    public var circleOffset: CGPoint = .init(x: -28.0, y: -2.0) { didSet { setNeedsLayout() } }
    
    override class var layerClass: AnyClass { CAGradientLayer.self }
    private var gradientLayer: CAGradientLayer { layer as! CAGradientLayer }
    
    private let circleLayer: CAShapeLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        self.backgroundColor = .clear
        
        gradientLayer.colors = [gradientColor1.cgColor, gradientColor2.cgColor]
        gradientLayer.startPoint = .init(x: 0.0, y: 0.0)
        gradientLayer.endPoint = .init(x: 1.0, y: 1.0)
        
        circleLayer.fillColor = circleColor.cgColor
        layer.addSublayer(circleLayer)
        
        layer.cornerRadius = 16.0
        
        layer.masksToBounds = true
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // position the circle so its center is at bottom-right corner
        //  offset circleOffset
        let r: CGRect = .init(x: bounds.maxX - circleDiameter * 0.5, y: bounds.maxY - circleDiameter * 0.5, width: circleDiameter, height: circleDiameter)
            .offsetBy(dx: circleOffset.x, dy: circleOffset.y)
        
        circleLayer.path = UIBezierPath(ovalIn: r).cgPath
    }
    
}

You are probably doing this:

mainView = UIView()

// set constraints on mainView

so, instead, we can do this:

mainView = MyCustomGradientView()

// set constraints on mainView

and we get this (for example):

enter image description here

We can add multiple instances, at various sizes:

enter image description here

and we can add subviews as we normally would:

enter image description here

and set / change colors if desired:

enter image description here