How can I set the UINavigationbar with gradient color?

前端 未结 11 697
花落未央
花落未央 2020-11-30 22:27

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, ide

相关标签:
11条回答
  • 2020-11-30 23:23

    This is the solution without using an intermediate CAGradientLayer, and just using CoreGraphics, in Swift 3.0.

    Essentially, the method creates a UIImage on the fly with the gradient colors passed and sets it.

    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()
        }
    }
    

    The defer statement makes this so much clean than prior versions. Be noted that CGGradient are available since iOS 8.0.

    Also, this creates the gradient from left to right, tweaking the parameters of drawLinearGradient (start and end) moves the locations. This is up for your implementation.

    0 讨论(0)
  • 2020-11-30 23:24

    In Swift 3

    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)
    
    func image(fromLayer layer: CALayer) -> UIImage {
        UIGraphicsBeginImageContext(layer.frame.size)
        layer.render(in: UIGraphicsGetCurrentContext()!)
        let outputImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return outputImage!
    }
    
    0 讨论(0)
  • 2020-11-30 23:31

    Swift 5

    • Includes status bar in gradient.
    • Doesn't use an image.
    • Uses transparency so content is visible through nav bar.
    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)
        }
    
    }
    
    0 讨论(0)
  • 2020-11-30 23:31

    This amazing tutorial from Lawrence Tan  shows how to set a gradient using barTintColor and no backgroundImage: https://medium.com/swift2go/add-gradient-to-navigation-bar-in-swift-9284fe91fea2

    Summary

    CAGradientLayer extension

    extension CAGradientLayer {
    
        class func primaryGradient(on view: UIView) -> UIImage? {
            let gradient = CAGradientLayer()
            let flareRed = UIColor(displayP3Red: 241.0/255.0, green: 39.0/255.0, blue: 17.0/255.0, alpha: 1.0)
            let flareOrange = UIColor(displayP3Red: 245.0/255.0, green: 175.0/255.0, blue: 25.0/255.0, alpha: 1.0)
            var bounds = view.bounds
            bounds.size.height += UIApplication.shared.statusBarFrame.size.height
            gradient.frame = bounds
            gradient.colors = [flareRed.cgColor, flareOrange.cgColor]
            gradient.startPoint = CGPoint(x: 0, y: 0)
            gradient.endPoint = CGPoint(x: 1, y: 0)
            return gradient.createGradientImage(on: view)
        }
    
        private func createGradientImage(on view: UIView) -> UIImage? {
            var gradientImage: UIImage?
            UIGraphicsBeginImageContext(view.frame.size)
            if let context = UIGraphicsGetCurrentContext() {
                render(in: context)
                gradientImage = UIGraphicsGetImageFromCurrentImageContext()?.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch)
            }
            UIGraphicsEndImageContext()
            return gradientImage
        }
    }
    

    Apply the gradient

    guard
        let navigationController = navigationController,
        let flareGradientImage = CAGradientLayer.primaryGradient(on: navigationController.navigationBar)
        else {
            print("Error creating gradient color!")
            return
        }
    
    navigationController.navigationBar.barTintColor = UIColor(patternImage: flareGradientImage)
    
    0 讨论(0)
  • 2020-11-30 23:32

    For 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!
        }
    }
    

    How to use

       self.navigationController?.navigationBar.setGradientBackground(colors: [
                UIColor.red.cgColor,
                UIColor.green.cgColor,
                UIColor.blue.cgColor
                ])
    
    0 讨论(0)
提交回复
热议问题