问题描述
我有一个带有 prefersLargeTitles = true
的 UINavigationController
我想将背景颜色应用到我的导航栏,并带有渐变蒙版,因此颜色基本上会淡化为较暗的版本.
I have a UINavigationController
with prefersLargeTitles = true
I'd like to apply a background colour to my nav bar, with a gradient mask so the colour essentially fades to a darker version.
我尝试创建一个 UIView
应用蒙版并呈现它.然而,这涉及将 UIView
渲染为 UIImage
,然后渲染为 UIColor
,以便我可以设置 barTintColor
.
I have tried to create a UIView
apply the mask and render this. This however involves rendering the UIView
as a UIImage
and then as a UIColor
so I can set the barTintColor
.
这仅在渲染 UIView
时有效,但在导航栏上设置时,行为不是我想要的.
This works when just rendering a UIView
but when setting it on the navigation bar, the behaviour is not as I would like.
我希望渐变填充整个绿色区域.
I would like that gradient to fill the entire green area.
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()
}
}
推荐答案
为了回答你的问题,我不认为 gradient.frame = frame
在你的 BrandedHeader
init 中正在做任何事情.我相信您需要在 layoutSubviews
中明确设置 height
道具.
To answer your question, I don't think gradient.frame = frame
in your BrandedHeader
init is doing anything. I believe you explicitly need to set the height
prop in layoutSubviews
.
类似 gradient.frame = CGRect(x: 0, y: 0, width: frame.width, height: 500)
- 虽然我没试过,所以请考虑调整值
Something like gradient.frame = CGRect(x: 0, y: 0, width: frame.width, height: 500)
- although I haven't tried that so please consider adjusting the values
我不确定这种方法是否是您想要实现的最佳方法,一旦我尝试了另一种方法来实现这一目标,我会回来更新这个答案.
I'm not sure if this approach is the best approach for what you are trying to achieve, I will comeback and update this answer once I have tried another way to achieve this.
这篇关于如何将 CAGradientLayer 应用于 UINavigationController 背景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!