I want to apply view gradient color but always failed.
I want to apply gradient view like this image:
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?
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):
We can add multiple instances, at various sizes:
and we can add subviews as we normally would:
and set / change colors if desired: