如何使用渐变颜色设置UINavigationbar?

Gha*_*mar 31 core-graphics uinavigationbar ios

我想设置UINavigationbar backgroundColor一个渐变颜色,我想通过颜色数组来设置它,以创建一个渐变,理想情况下,作为可访问的方法UINavigationBar,将其颜色更改为此渐变.

有什么建议?(除了手动设置图像作为导航栏的背景图像)

Vas*_*huk 64

细节

Xcode 8.3.1,Swift 3.1

扩展CAGradientLayer

class UINavigationBarGradientView: UIView {

    enum Point {
        case topRight, topLeft
        case bottomRight, bottomLeft
        case custion(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 .custion(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)
    }
}
Run Code Online (Sandbox Code Playgroud)

扩展UINavigationBar

navigationBar.setGradientBackground(colors: [.lightGray, .red], startPoint: .topLeft, endPoint: .bottomRight)
Run Code Online (Sandbox Code Playgroud)

用法

class ViewController

class UINavigationBarGradientView: UIView {

    enum Point {
        case topRight, topLeft
        case bottomRight, bottomLeft
        case custion(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 .custion(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)
    }
}
Run Code Online (Sandbox Code Playgroud)

Main.storyboard

在此输入图像描述

结果

在此输入图像描述

  • 您可以将`UINavigationBar扩展名'改进为`updatedFrame.size.height + = self.frame.origin.y`以匹配新的iPhone X. (3认同)

Ash*_*kad 25

创建渐变图层并将其添加为导航栏的背景.

    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];
Run Code Online (Sandbox Code Playgroud)

用于从图层创建图像.

- (UIImage *)imageFromLayer:(CALayer *)layer
{
    UIGraphicsBeginImageContext([layer frame].size);

    [layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return outputImage;
}
Run Code Online (Sandbox Code Playgroud)

还有一件事,github中有一个库:CRGradientNavigationBar你也可以使用这个库.


pab*_*ros 20

Swift 3Swift 4中:

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)
Run Code Online (Sandbox Code Playgroud)

用于从图层创建图像:

func image(fromLayer layer: CALayer) -> UIImage {
    UIGraphicsBeginImageContext(layer.frame.size)

    layer.render(in: UIGraphicsGetCurrentContext()!)

    let outputImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return outputImage!
}
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

用于从图层创建图像:

func image(fromLayer layer: CALayer) -> UIImage {    
    UIGraphicsBeginImageContext(layer.frame.size)

    layer.renderInContext(UIGraphicsGetCurrentContext()!)

    let outputImage = UIGraphicsGetImageFromCurrentImageContext()

     UIGraphicsEndImageContext()

    return outputImage!
}
Run Code Online (Sandbox Code Playgroud)


Can*_*Can 10

这是没有使用中间件的解决方案CAGradientLayer,只是CoreGraphics在Swift 3.0中使用.

本质上,该方法UIImage使用渐变颜色动态创建并设置它.

extension UINavigationBar
{
    /// Applies a background gradient with the given colors
    func apply(gradient colors : [UIColor]) {
        var frameAndStatusBar: CGRect = self.bounds
        frameAndStatusBar.size.height += 20 // add 20 to account for the status bar

        setBackgroundImage(UINavigationBar.gradient(size: frameAndStatusBar.size, colors: colors), for: .default)
    }

    /// Creates a gradient image with the given settings
    static func gradient(size : CGSize, colors : [UIColor]) -> UIImage?
    {
        // Turn the colors into CGColors
        let cgcolors = colors.map { $0.cgColor }

        // Begin the graphics context
        UIGraphicsBeginImageContextWithOptions(size, true, 0.0)

        // If no context was retrieved, then it failed
        guard let context = UIGraphicsGetCurrentContext() else { return nil }

        // From now on, the context gets ended if any return happens
        defer { UIGraphicsEndImageContext() }

        // Create the Coregraphics gradient
        var locations : [CGFloat] = [0.0, 1.0]
        guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: cgcolors as NSArray as CFArray, locations: &locations) else { return nil }

        // Draw the gradient
        context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: [])

        // Generate the image (the defer takes care of closing the context)
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}
Run Code Online (Sandbox Code Playgroud)

defer声明使其比以前的版本更加干净.请注意,CGGradient自iOS 8.0起可用.

此外,这会从左到右创建渐变,调整drawLinearGradient(startend)参数移动位置.这取决于您的实施.


Har*_*kar 5

对于Swift 4.2

extension UINavigationBar {
    func setGradientBackground(colors: [Any]) {
        let gradient: CAGradientLayer = CAGradientLayer()
        gradient.locations = [0.0 , 0.5, 1.0]
        gradient.startPoint = CGPoint(x: 0.0, y: 1.0)
        gradient.endPoint = CGPoint(x: 1.0, y: 1.0)

        var updatedFrame = self.bounds
        updatedFrame.size.height += self.frame.origin.y
        gradient.frame = updatedFrame
        gradient.colors = colors;
        self.setBackgroundImage(self.image(fromLayer: gradient), for: .default)
    }

    func image(fromLayer layer: CALayer) -> UIImage {
        UIGraphicsBeginImageContext(layer.frame.size)
        layer.render(in: UIGraphicsGetCurrentContext()!)
        let outputImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return outputImage!
    }
}
Run Code Online (Sandbox Code Playgroud)

如何使用

   self.navigationController?.navigationBar.setGradientBackground(colors: [
            UIColor.red.cgColor,
            UIColor.green.cgColor,
            UIColor.blue.cgColor
            ])
Run Code Online (Sandbox Code Playgroud)


Azh*_*ikh 5

环球银行金融电信协会5

要使导航栏和状态栏也具有水平渐变背景......只需将此代码放入视图控制器的viewDidLoad()方法中即可。

    self.navigationItem.title = "Gradiant Back Ground"
    let gradientLayer = CAGradientLayer()
    var updatedFrame = self.navigationController!.navigationBar.bounds
    updatedFrame.size.height += UIApplication.shared.statusBarFrame.size.height
    gradientLayer.frame = updatedFrame
    gradientLayer.colors = [UIColor.green.cgColor, UIColor.blue.cgColor] // start color and end color
    gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0) // Horizontal gradient start
    gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0) // Horizontal gradient end
    UIGraphicsBeginImageContext(gradientLayer.bounds.size)
    gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    self.navigationController!.navigationBar.setBackgroundImage(image, for: UIBarMetrics.default)
Run Code Online (Sandbox Code Playgroud)

渐变看起来像这样

输出渐变将如下所示。


Jim*_*y_m 5

斯威夫特 5

  • 包括渐变状态栏。
  • 不使用图像。
  • 使用透明度,因此通过导航栏可以看到内容。
extension UINavigationBar {

    func addGradient(_ toAlpha: CGFloat, _ color: UIColor) {
        let gradient = CAGradientLayer()
        gradient.colors = [
            color.withAlphaComponent(toAlpha).cgColor,
            color.withAlphaComponent(toAlpha).cgColor,
            color.withAlphaComponent(0).cgColor
        ]
        gradient.locations = [0, 0.8, 1]
        var frame = bounds
        frame.size.height += UIApplication.shared.statusBarFrame.size.height
        frame.origin.y -= UIApplication.shared.statusBarFrame.size.height
        gradient.frame = frame
        layer.insertSublayer(gradient, at: 1)
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 这个例子不包括大标题、方向变化...... (2认同)