iOS 11中带有大标题导航栏的自定义背景图像

iOS 11中带有大标题导航栏的自定义背景图像,ios,swift,uinavigationbar,ios11,Ios,Swift,Uinavigationbar,Ios11,如何在iOS 11中为大标题导航栏设置自定义背景图像?我正在使用一个自定义子类,我已经在故事板中分配给NavigationController 以下是创建自定义导航栏的方式: class CustomNavigationController: UINavigationController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup afte

如何在iOS 11中为大标题导航栏设置自定义背景图像?我正在使用一个自定义子类,我已经在故事板中分配给NavigationController

以下是创建自定义导航栏的方式:

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.navigationBar.tintColor = UIColor(red:1, green:1, blue:1, alpha:0.6)
        self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
        if #available(iOS 11.0, *) {
            self.navigationBar.prefersLargeTitles = true
            self.navigationItem.largeTitleDisplayMode = .automatic
            self.navigationBar.largeTitleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
            self.navigationBar.barTintColor = UIColor.green
        }
        self.navigationBar.isTranslucent = false
        self.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navigationBarBackground"), for: .default)
        self.navigationBar.shadowImage = #imageLiteral(resourceName: "navigationBarShadow")
    }
}
奇怪的是,
setBackgroundImage(图像,例如:.default)
对大标题不起作用。它以前在iOS 10上工作过,如果我旋转iPhone(并激活小导航栏),背景会回来吗

编辑:
backgroundImage
仍被渲染,但不知何故被隐藏。只有当您开始滚动并且出现“正常”导航栏时,背景图像才可见。在这种情况下,
BartinColor
也被完全忽略。

在iOS 11中,如果您使用大标题,则不再需要设置背景图像(删除其声明)。相反,你需要使用颜色

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.navigationBar.tintColor = UIColor(red:1, green:1, blue:1, alpha:0.6)
        self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
        if #available(iOS 11.0, *) {
            self.navigationBar.prefersLargeTitles = true
            self.navigationItem.largeTitleDisplayMode = .automatic
            self.navigationBar.largeTitleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
            self.navigationBar.barTintColor = UIColor(red:1, green:1, blue:1, alpha:1)
        }
        else {
            self.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navigationBarBackground"), for: .default)                
        }
        self.navigationBar.shadowImage = #imageLiteral(resourceName: "navigationBarShadow")
        self.navigationBar.isTranslucent = false
    }
}

我也有同样的问题,由

移除setBackgroundImage并将Barint颜色与图案图像一起使用

let bgimage = imageWithGradient(startColor: UIColor.red, endColor: UIColor.yellow, size: CGSize(width: UIScreen.main.bounds.size.width, height: 1))
self.navigationBar.barTintColor = UIColor(patternImage: bgimage!)
使用渐变颜色获取图像

func imageWithGradient(startColor:UIColor, endColor:UIColor, size:CGSize, horizontally:Bool = true) -> UIImage? {

    let gradientLayer = CAGradientLayer()
    gradientLayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
    gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
    if horizontally {
        gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
    } else {
        gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
        gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
    }

    UIGraphicsBeginImageContext(gradientLayer.bounds.size)
    gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

在Xamarin,情况是这样的:

this.NavigationBar.BackgroundColor = UIColor.Clear;

      var gradientLayer = new CAGradientLayer
      {
        Frame = new CGRect(0, 0, UIApplication.SharedApplication.StatusBarFrame.Width,
              UIApplication.SharedApplication.StatusBarFrame.Height + this.NavigationBar.Frame.Height),
        Colors = new CGColor[]
              {Constants.Defaults.Navigation.RealBlueColor.ToCGColor(), Constants.Defaults.Navigation.RealBlueColor.ToCGColor()}
      };

      UIGraphics.BeginImageContext(gradientLayer.Bounds.Size);
      gradientLayer.RenderInContext((UIGraphics.GetCurrentContext()));
      UIImage image = UIGraphics.GetImageFromCurrentImageContext();
      UIGraphics.EndImageContext();

      this.View.Layer.InsertSublayer(gradientLayer, 0);
      this.NavigationBar.BarTintColor = UIColor.FromPatternImage(image);
this.View.Layer.Insert是可选的。当我在导航栏上上上下“卷曲”图像时,我需要它。请尝试以下代码(Swift 4.0):

在viewDidLoad()中

self.navigationController?.navigationBar.titleTextAttributes=[NSAttributedStringKey.foregroundColor:UIColor.black]
如果可用(iOS 11.0,*){
self.navigationController?.navigationBar.prefersLargeTitles=true
self.navigationItem.LarGetTitleDisplayMode=.automatic
self.navigationController?.navigationBar.largeTitleTextAttributes=[NSAttributedStringKey.foregroundColor:UIColor.black]
}否则{

//iOS借鉴奥尔德林门德斯的答案——该解决方案适用于水平梯度

对于垂直渐变,我可以使用oldrinmendez回答中的相同函数,在scrollViewDidScroll中再次调用它。这会在用户滚动时不断调整渐变图像的高度

从oldrinmendez的函数开始:

func imageWithGradient(startColor:UIColor, endColor:UIColor, size:CGSize, horizontally:Bool) -> UIImage? {

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
        if horizontally {
            gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        } else {
            gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
            gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
        }

        UIGraphicsBeginImageContext(gradientLayer.bounds.size)
        gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
func updateImageWithGradient() {

        let navBarHeight  = self.navigationController?.navigationBar.frame.size.height
        let statusBarHeight = UIApplication.shared.statusBarFrame.height
        let heightAdjustment: CGFloat = 2

        let gradientHeight = navBarHeight! + statusBarHeight + heightAdjustment

        let bgimage = imageWithGradient(startColor: UIColor.red, endColor: UIColor.orange, size: CGSize(width: UIScreen.main.bounds.size.width, height: gradientHeight), horizontally: false)
        navigationController?.navigationBar.barTintColor = UIColor(patternImage: bgimage!)
    }
创建一个更新函数,用您想要的选项调用它:

func imageWithGradient(startColor:UIColor, endColor:UIColor, size:CGSize, horizontally:Bool) -> UIImage? {

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
        if horizontally {
            gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        } else {
            gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
            gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
        }

        UIGraphicsBeginImageContext(gradientLayer.bounds.size)
        gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
func updateImageWithGradient() {

        let navBarHeight  = self.navigationController?.navigationBar.frame.size.height
        let statusBarHeight = UIApplication.shared.statusBarFrame.height
        let heightAdjustment: CGFloat = 2

        let gradientHeight = navBarHeight! + statusBarHeight + heightAdjustment

        let bgimage = imageWithGradient(startColor: UIColor.red, endColor: UIColor.orange, size: CGSize(width: UIScreen.main.bounds.size.width, height: gradientHeight), horizontally: false)
        navigationController?.navigationBar.barTintColor = UIColor(patternImage: bgimage!)
    }
最后将更新功能添加到scrollViewDidScroll&ViewDidApper:使用ViewDidDisplay,以便返回正确的导航栏高度

override func viewDidAppear(_ animated: Bool) {
        updateImageWithGradient()
    }

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
     DispatchQueue.main.async {
        updateImageWithGradient()
       }
    }

更改barTint对我不起作用,所以我更改了navigationBar中的层

 navigationBar.layer.backgroundColor = UIColor(patternImage:
        UIImage(named: "BG-Roof1")!.resizableImage(withCapInsets:
            UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0), resizingMode: .stretch)).cgColor

我终于找到了解决方案!

编辑:适用于iOS 13及更高版本


您可以在视图出现之前使用它,例如:在viewDidLoad()方法中:


您所需要的只是:

  • 创建UINavigationBarAppearance实例:

    let largeTitleAppearance = UINavigationBarAppearance() 
    
    苹果文档:

    UINavigationBarAppearance-用于自定义导航栏外观的对象


  • 配置它:

    largeTitleAppearance.configureWithOpaqueBackground()
    
    这里的“不透明”是因为我们想要设置彩色图像(但实际上这并不重要,您将设置什么配置)


  • 设置背景图像:

    largeTitleAppearance.backgroundImage = UIImage(named: "BackgroundImage.png") // Set here image that you need
    

  • 将我们的LarGetTitleAppearance对象分配给standardAppearance和ScrolledAppearance导航栏的字段:

    self.navigationBar.standardAppearance = largeTitleAppearance // For large-navigationBar condition when it is collapsed
    self.navigationBar.scrollEdgeAppearance = largeTitleAppearance // For large-navigationBar condition when it is expanded
    
    苹果文档:

    .standardAppearance-标准高度导航栏的外观设置

    .scrollEdgeAppearance-任何可滚动内容的边缘到达导航栏的匹配边缘时使用的外观设置




  • 这对我很有帮助:

    hi@alexkaessner。你找到问题的解决方案了吗?@OceanBlue否!:/我刚刚检查了一下新的导航栏。对于显示的大布局,似乎有一个完全不同的视图,但该视图没有改变。可以设置导航栏背景色或BartinColor。但不幸的是,我不能t设置导航栏背景图像。这是ios 11的错误吗?你知道什么吗?@OceanBlue我刚刚添加了一些分析信息,但似乎是个错误。我稍后将向苹果提交报告!@Tulleb一点也不。苹果将其标记为“33345493的副本”,但问题仍然悬而未决。感谢您的帖子,但这不是一个真正的解决方案。我还进行了一些测试和分析,似乎我必须坚持使用传统的导航栏(目前)。感谢您的回答。您知道导航栏背景图像的大小吗(示例中的navigationBarBackground)?我也尝试过,但我希望图像被拉伸而不是平铺。我的图像有一个渐变…或者有没有办法更改
    模式图像:
    ?好的,我现在已经测试过了,问题仍然是平铺。如果我旋转iPhone,渐变太短并且重复。而且“水平:false”也不起作用正确。这只是一个橙色的条背景。救世主:-)如果我们想拥有自己的背景图像,没有图案或渐变色,那该怎么办?我只想展示一幅简单的图像。你知道导航栏背景图像的大小吗?这对常规标题大小和大标题大小都非常有效,谢谢。不,这里同样适用于iOS 12。这是更正iOS 13中的解决方案。UIColor(图案图像:)解决方案只是黑客。太棒了,这是正确的解决方案!感谢您将其分享到这篇旧帖子。疯狂的是,苹果花了很长时间才介绍了这一点。顺便说一句,如果您需要更改背景图像拉伸/定位,也可以看看SwiftUI的作品!@HarryJ Ohh,这是我需要的。您需要使用UIHostingController还是你是另一种方式吗?