I want to set the UINavigationbar
backgroundColor
to a gradient color where I would like to set it via an array of colors to create a Gradient, ideally, as accessible methods inside UINavigationBar
to change its color to this gradient.
Any suggestions? (Aside from setting an image manually as the background image of the navigation bar)
Select the Gradient tool in the toolbar. In the selected artwork you'll see the gradient annotator, which shows the gradient slider and the color stops. Double-click a color stop on the artwork to edit the color, drag the color stops, click beneath the gradient slider to add new color stops, and more.
class UINavigationBarGradientView: UIView {
enum Point {
case topRight, topLeft
case bottomRight, bottomLeft
case custom(point: CGPoint)
var point: CGPoint {
switch self {
case .topRight: return CGPoint(x: 1, y: 0)
case .topLeft: return CGPoint(x: 0, y: 0)
case .bottomRight: return CGPoint(x: 1, y: 1)
case .bottomLeft: return CGPoint(x: 0, y: 1)
case .custom(let point): return point
}
}
}
private weak var gradientLayer: CAGradientLayer!
convenience init(colors: [UIColor], startPoint: Point = .topLeft,
endPoint: Point = .bottomLeft, locations: [NSNumber] = [0, 1]) {
self.init(frame: .zero)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = frame
layer.addSublayer(gradientLayer)
self.gradientLayer = gradientLayer
set(colors: colors, startPoint: startPoint, endPoint: endPoint, locations: locations)
backgroundColor = .clear
}
func set(colors: [UIColor], startPoint: Point = .topLeft,
endPoint: Point = .bottomLeft, locations: [NSNumber] = [0, 1]) {
gradientLayer.colors = colors.map { $0.cgColor }
gradientLayer.startPoint = startPoint.point
gradientLayer.endPoint = endPoint.point
gradientLayer.locations = locations
}
func setupConstraints() {
guard let parentView = superview else { return }
translatesAutoresizingMaskIntoConstraints = false
topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true
leftAnchor.constraint(equalTo: parentView.leftAnchor).isActive = true
parentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
parentView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
}
override func layoutSubviews() {
super.layoutSubviews()
guard let gradientLayer = gradientLayer else { return }
gradientLayer.frame = frame
superview?.addSubview(self)
}
}
extension UINavigationBar {
func setGradientBackground(colors: [UIColor],
startPoint: UINavigationBarGradientView.Point = .topLeft,
endPoint: UINavigationBarGradientView.Point = .bottomLeft,
locations: [NSNumber] = [0, 1]) {
guard let backgroundView = value(forKey: "backgroundView") as? UIView else { return }
guard let gradientView = backgroundView.subviews.first(where: { $0 is UINavigationBarGradientView }) as? UINavigationBarGradientView else {
let gradientView = UINavigationBarGradientView(colors: colors, startPoint: startPoint,
endPoint: endPoint, locations: locations)
backgroundView.addSubview(gradientView)
gradientView.setupConstraints()
return
}
gradientView.set(colors: colors, startPoint: startPoint, endPoint: endPoint, locations: locations)
}
}
navigationBar.setGradientBackground(colors: [.lightGray, .red], startPoint: .topLeft, endPoint: .bottomRight)
Create gradient layer and add it as background of navigation bar.
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.navigationController.navigationBar.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor blackColor] CGColor], nil];
[self.navigationController.navigationBar setBackgroundImage:[self imageFromLayer:gradient] forBarMetrics:UIBarMetricsDefault];
For creating image from layer.
- (UIImage *)imageFromLayer:(CALayer *)layer
{
UIGraphicsBeginImageContext([layer frame].size);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage;
}
One more thing, there is one library available in github : CRGradientNavigationBar you can also use this library.
In Swift 3, Swift 4 and Swift 5:
let gradient = CAGradientLayer()
let sizeLength = UIScreen.main.bounds.size.height * 2
let defaultNavigationBarFrame = CGRect(x: 0, y: 0, width: sizeLength, height: 64)
gradient.frame = defaultNavigationBarFrame
gradient.colors = [UIColor.white.cgColor, UIColor.black.cgColor]
UINavigationBar.appearance().setBackgroundImage(self.image(fromLayer: gradient), for: .default)
For creating image from layer:
func image(fromLayer layer: CALayer) -> UIImage {
UIGraphicsBeginImageContext(layer.frame.size)
layer.render(in: UIGraphicsGetCurrentContext()!)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage!
}
In Swift 2:
let gradient = CAGradientLayer()
let sizeLength = UIScreen.mainScreen().bounds.size.height * 2
let defaultNavigationBarFrame = CGRectMake(0, 0, sizeLength, 64)
gradient.frame = defaultNavigationBarFrame
gradient.colors = [UIColor.whiteColor().CGColor, UIColor.blackColor().CGColor]
UINavigationBar.appearance().setBackgroundImage(self.image(fromLayer: gradient), forBarMetrics: .Default)
For creating image from layer:
func image(fromLayer layer: CALayer) -> UIImage {
UIGraphicsBeginImageContext(layer.frame.size)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage!
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With