You can use this complete extension for all view:
// MARK: - Gradient
extension UIView {
enum axis {
case vertical, horizontal, custom(angle: CGFloat)
}
func setGradientBackgroundColor(colors: [UIColor], axis: axis, cornerRadius: CGFloat? = nil, apply: ((UIView) -> ())? = nil) {
layer.sublayers?.filter { $0.name == "gradientLayer" }.forEach { $0.removeFromSuperlayer() }
self.layoutIfNeeded()
let cgColors = colors.map { $0.cgColor }
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = cgColors
gradient.name = "gradientLayer"
gradient.locations = [0.0, 1.0]
switch axis {
case .horizontal:
gradient.startPoint = CGPoint(x: 0.0, y: 1.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
case .custom(let angle):
calculatePoints(for: angle, gradient: gradient)
default:
break
}
gradient.frame = self.bounds
self.layer.insertSublayer(gradient, at: 0)
guard let cornerRadius = cornerRadius else { return }
let circularPath = CGMutablePath()
circularPath.move(to: CGPoint.init(x: cornerRadius, y: 0))
circularPath.addLine(to: CGPoint.init(x: self.bounds.width - cornerRadius, y: 0))
circularPath.addQuadCurve(to: CGPoint.init(x: self.bounds.width, y: cornerRadius), control: CGPoint.init(x: self.bounds.width, y: 0))
circularPath.addLine(to: CGPoint.init(x: self.bounds.width, y: self.bounds.height - cornerRadius))
circularPath.addQuadCurve(to: CGPoint.init(x: self.bounds.width - cornerRadius, y: self.bounds.height), control: CGPoint.init(x: self.bounds.width, y: self.bounds.height))
circularPath.addLine(to: CGPoint.init(x: cornerRadius, y: self.bounds.height))
circularPath.addQuadCurve(to: CGPoint.init(x: 0, y: self.bounds.height - cornerRadius), control: CGPoint.init(x: 0, y: self.bounds.height))
circularPath.addLine(to: CGPoint.init(x: 0, y: cornerRadius))
circularPath.addQuadCurve(to: CGPoint.init(x: cornerRadius, y: 0), control: CGPoint.init(x: 0, y: 0))
let maskLayer = CAShapeLayer()
maskLayer.path = circularPath
maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
maskLayer.fillColor = UIColor.red.cgColor
self.layer.mask = maskLayer
apply?(self)
}
func calculatePoints(for angle: CGFloat, gradient: CAGradientLayer) {
var ang = (-angle).truncatingRemainder(dividingBy: 360)
if ang < 0 { ang = 360 + ang }
let n: CGFloat = 0.5
switch ang {
case 0...45, 315...360:
let a = CGPoint(x: 0, y: n * tanx(ang) + n)
let b = CGPoint(x: 1, y: n * tanx(-ang) + n)
gradient.startPoint = a
gradient.endPoint = b
case 45...135:
let a = CGPoint(x: n * tanx(ang - 90) + n, y: 1)
let b = CGPoint(x: n * tanx(-ang - 90) + n, y: 0)
gradient.startPoint = a
gradient.endPoint = b
case 135...225:
let a = CGPoint(x: 1, y: n * tanx(-ang) + n)
let b = CGPoint(x: 0, y: n * tanx(ang) + n)
gradient.startPoint = a
gradient.endPoint = b
case 225...315:
let a = CGPoint(x: n * tanx(-ang - 90) + n, y: 0)
let b = CGPoint(x: n * tanx(ang - 90) + n, y: 1)
gradient.startPoint = a
gradient.endPoint = b
default:
let a = CGPoint(x: 0, y: n)
let b = CGPoint(x: 1, y: n)
gradient.startPoint = a
gradient.endPoint = b
}
}
private func tanx(_ π½: CGFloat) -> CGFloat {
return tan(π½ * CGFloat.pi / 180)
}
}
Using:
btn.setGradientBackgroundColor(colors: [.softBlue, .seaBlue], axis: .horizontal, cornerRadius: 5) { view in
guard let btn = view as? UIButton, let imageView = btn.imageView else { return }
btn.bringSubviewToFront(imageView) // To display imageview of button
}