How can I set the UINavigationbar with gradient color?

前端 未结 11 735
花落未央
花落未央 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:14

    Details

    • Xcode 11.4 (11E146), swift 5
    • Tested on iOS 13.1, 12.2, 11.0.1

    Solution

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

    Usage

    navigationBar.setGradientBackground(colors: [.lightGray, .red], startPoint: .topLeft, endPoint: .bottomRight)
    

提交回复
热议问题