Gradient is natively using CAGradientLayer witch is a CALayer not an UIView. So view layouts are not affecting it.
A custom class
You can use this class I wrote:
class GradientView: UIView {
var colors: [UIColor]? { didSet { syncColors() } }
var direction: GradientDirection = .topToBottom {
didSet {
layer.startPoint = direction.startPoint
layer.endPoint = direction.endPoint
}
}
enum GradientDirection {
case rightToLeft
case leftToRight
case bottomToTop
case topToBottom
case custom(startPoint: CGPoint,endPoint: CGPoint)
var startPoint: CGPoint {
switch self {
case .rightToLeft: return CGPoint(x: 1, y: 0)
case .leftToRight: return .zero
case .bottomToTop: return CGPoint(x: 0, y: 1)
case .topToBottom: return .zero
case .custom(let startPoint, _): return startPoint
}
}
var endPoint: CGPoint {
switch self {
case .rightToLeft: return .zero
case .leftToRight: return CGPoint(x: 1, y: 0)
case .bottomToTop: return .zero
case .topToBottom: return CGPoint(x: 0, y: 1)
case .custom(_, let endPoint): return endPoint
}
}
static var interfaceDirection: GradientDirection {
switch UIApplication.shared.userInterfaceLayoutDirection {
case .leftToRight: return .leftToRight
case .rightToLeft: return .rightToLeft
}
}
}
override class var layerClass: AnyClass { return CAGradientLayer.self }
override var layer: CAGradientLayer { return super.layer as! CAGradientLayer }
override func layoutSubviews() { syncColors() }
private func syncColors() { layer.colors = colors?.map() { $0.cgColor } }
}
Simplifier class
With the help of this simple class:
enum GradientDirection {
case rightToLeft
case leftToRight
case bottomToTop
case topToBottom
case custom(startPoint: CGPoint,endPoint: CGPoint)
var startPoint: CGPoint {
switch self {
case .rightToLeft: return CGPoint(x: 1, y: 0)
case .leftToRight: return .zero
case .bottomToTop: return CGPoint(x: 0, y: 1)
case .topToBottom: return .zero
case .custom(let startPoint, _): return startPoint
}
}
var endPoint: CGPoint {
switch self {
case .rightToLeft: return .zero
case .leftToRight: return CGPoint(x: 1, y: 0)
case .bottomToTop: return .zero
case .topToBottom: return CGPoint(x: 0, y: 1)
case .custom(_, let endPoint): return endPoint
}
}
static var interfaceDirection: GradientDirection {
switch UIApplication.shared.userInterfaceLayoutDirection {
case .leftToRight: return .leftToRight
case .rightToLeft: return .rightToLeft
}
}
}
So then you have a normal view that reacts to any layout notifications from the super view.
Usage
Just add subview and set the class to the GradientView and layout with autolayout or any other layout you want.
or with code:
let gradientView: GradientView = {
let gradientView = GradientView(frame: self.frame)
gradientView.colors = [
UIColor.black.withAlphaComponent(1),
UIColor.black.withAlphaComponent(0)
]
gradientView.direction = .bottomToTop
return gradientView
}()
Note that you need to remove the original backgroundColor of the view if you want it to have some transparency.
self.layer.layoutIfNeeded()orself.layer.layoutSublayers()at the end oflayoutSubviews()to adapt the layer geometry to any revised view geometry. - flanker