Как я могу применить CAGradientLayer к фону UINavigationController - PullRequest
0 голосов
/ 30 марта 2019

У меня есть UINavigationController с prefersLargeTitles = true Я хотел бы применить цвет фона к моей навигационной панели с маской градиента, чтобы цвет по существу исчезал для более темной версии.

Я пробовалчтобы создать UIView примените маску и визуализируйте это.Это, однако, включает в себя рендеринг UIView как UIImage, а затем как UIColor, поэтому я могу установить barTintColor.

. Это работает, когда просто рендерит UIView, но при установке его напанель навигации, поведение не такое, как хотелось бы.

Current Results

Мне бы хотелось, чтобы этот градиент заполнил всю зеленую область.

class BaseViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        configureNavigationBar()
    }

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

    func hideNavigationBar() {
        navigationController?.setNavigationBarHidden(true, animated: false)
    }

    func showNavigationBar() {
        navigationController?.setNavigationBarHidden(false, animated: false)
    }

    private func configureNavigationBar() {
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationController?.navigationBar.isTranslucent = false
        navigationItem.title = "Home"

        let v = BrandedHeader(frame: .zero)
        v.frame = navigationController?.navigationBar.frame ?? .zero

        navigationController?.navigationBar.barTintColor = UIColor(patternImage: v.asImage()!)
    }
}

extension UIImage {
    static func usingHex(_ hex: String) -> UIImage {
        let color = UIColor.usingHex(hex)
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context!.setFillColor(color.cgColor)
        context!.fill(rect)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }
}

extension UIView {

    func asImage() -> UIImage? {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                layer.render(in: rendererContext.cgContext)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
            defer { UIGraphicsEndImageContext() }
            guard let currentContext = UIGraphicsGetCurrentContext() else {
                return nil
            }
            self.layer.render(in: currentContext)
            return UIGraphicsGetImageFromCurrentImageContext()
        }
    }
}

class BrandedHeader: UIView {
    let gradient: CAGradientLayer = CAGradientLayer()

    override init (frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = UIColor.green

        gradient.frame = frame
        gradient.colors = [UIColor.clear, UIColor.black.withAlphaComponent(0.3)].map { $0.cgColor }
        gradient.locations = [0.0, 0.7]
        gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
        gradient.endPoint = CGPoint(x: 1.0, y: 0.0)
        layer.insertSublayer(gradient, at: 0)
    }

    required init?(coder aDecoder: NSCoder) {
        return nil
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradient.frame = frame
        gradient.removeAllAnimations()
    }
}

Ответы [ 2 ]

1 голос
/ 30 марта 2019

Чтобы ответить на ваш вопрос, я не думаю, что gradient.frame = frame в вашем BrandedHeader init что-то делает.Я считаю, что вам явно необходимо установить height опору в layoutSubviews.

Что-то вроде gradient.frame = CGRect(x: 0, y: 0, width: frame.width, height: 500) - хотя я не пробовал этого, поэтому, пожалуйста, рассмотрите возможность корректировки значений

I 'Я не уверен, является ли этот подход лучшим подходом к тому, чего вы пытаетесь достичь, я вернусь и обновлю этот ответ, как только попробую другой способ достижения этого.

0 голосов
/ 30 марта 2019

Следующий код показывает, как сделать панель навигации с градиентными цветами.Он протестирован под Swift 5.

// ViewController.swift //
import UIKit

class ViewController: UIViewController {
    // MARK: - Variables

    // MARK: - IBOutlet

    // MARK: - IBAction

    // MARK: - Life cycle
    override func viewDidLoad() {
        super.viewDidLoad()

        let titleString = "Home"
        let navBar = navigationController!.navigationBar
        let atext = NSMutableAttributedString(string: titleString)
        let range = NSMakeRange(0, titleString.count)
        atext.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], range: range)
        atext.addAttributes([NSAttributedString.Key.strokeColor: UIColor.yellow], range: range)
        atext.addAttributes([NSAttributedString.Key.strokeWidth: NSNumber.init(value: -1.0)], range: range)
        let titleLabel: UILabel = UILabel.init(frame: CGRect(x: 50, y: 3, width: 220-100, height: 44))
        titleLabel.attributedText = atext
        titleLabel.textAlignment = NSTextAlignment.center
        titleLabel.font = UIFont(name: "Helvetica", size: 24.0)
        self.navigationItem.titleView = titleLabel

        let rect = CGRect(x: 0, y: -20, width: (self.navigationController?.navigationBar.bounds.width)!, height: (self.navigationController?.navigationBar.bounds.height)! + 20)
        let colors = [UIColor.blue, UIColor.purple, UIColor.red]
        let points: [CGFloat] = [0.1, 0.5, 0.9]
        let gradientView = GradientView(frame: rect, backColor: UIColor.white, gradientColors: colors, points: points, isVertical: true)
        gradientView.backgroundColor = UIColor.white
        navBar.insertSubview(gradientView, at: 1)

        navBar.layer.shadowColor = UIColor.black.cgColor
        navBar.layer.shadowRadius = 4.0
        navBar.layer.shadowOpacity = 0.6
        navBar.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
    }
}

// GradientView.swift (subclass of UIView) //
import UIKit

class GradientView: UIView {
    var backColor: UIColor
    var gradientColors: [UIColor]
    var points: [CGFloat]
    var isVertical: Bool

    init(frame: CGRect, backColor: UIColor, gradientColors: [UIColor], points: [CGFloat], isVertical: Bool) {
        self.backColor = backColor
        self.gradientColors = gradientColors
        self.points = points
        self.isVertical = isVertical
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        backColor.set()
        UIRectFill(rect)

        let gradient: CAGradientLayer = CAGradientLayer()
        gradient.frame = self.bounds

        var colors = [CGColor]()
        for i in 0..<gradientColors.count {
            let color = gradientColors[i]
            colors.append(color.cgColor)
        }
        gradient.colors = colors

        var locations = [CGFloat]()
        for i in 0..<points.count {
            let point = points[i]
            locations.append(point)
        }
        gradient.locations = locations as [NSNumber]
        if !isVertical {
            gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
            gradient.endPoint = CGPoint(x: 1.0, y: 0.0)
        }
        layer.addSublayer(gradient)
    }
}

enter image description here

Если вы хотите использовать цвета по горизонтали (слева направо), установите переключатель isVerticalложно.

enter image description here

...