在iOS 11中使用大标题NavigationBar自定义背景图像

时间:2017-09-13 11:52:31

标签: ios swift uinavigationbar ios11

如何在iOS 11中为大型标题NavigationBar设置自定义背景图像?我使用了自定义的子类,我已将其分配给故事板中的navigationControllers。

这是我创建自定义导航栏的方式:

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(image, for: .default)对大型游戏并不起作用。它之前适用于iOS 10,如果我旋转iPhone(并激活小型NavBar)背景又回来了?

修改 backgroundImage仍然呈现,但不知何故隐藏了。只有当你开始滚动并且正常"出现导航栏,backgroundImage可见。在这种情况下,barTintColor也完全被忽略。 screenshot GIF

7 个答案:

答案 0 :(得分:16)

我有同样的问题,由

修复

删除setBackgroundImage并使用带图案图像的barTint颜色

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
}

答案 1 :(得分:5)

在iOS 11中,如果使用大型标题,则不再需要设置BackgroundImage(删除其声明)。相反,你需要使用BarTintColor。

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

答案 2 :(得分:5)

最后我找到了解决方法!

编辑:可在iOS 13及更高版本上运行


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

    override func viewDidLoad()
    {
        super.viewDidLoad()

        let largeTitleAppearance = UINavigationBarAppearance() 

        largeTitleAppearance.configureWithOpaqueBackground()
        largeTitleAppearance.backgroundImage = UIImage(named: "BackgroundImage.png")

        self.navigationBar.standardAppearance = largeTitleAppearance
        self.navigationBar.scrollEdgeAppearance = largeTitleAppearance
    }

您需要的是:

  1. 创建UINavigationBarAppearance实例:

    let largeTitleAppearance = UINavigationBarAppearance() 
    

    Apple文档:

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


  1. 配置它:

    largeTitleAppearance.configureWithOpaqueBackground()
    

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


  1. 设置背景图片:

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

  1. 将我们的 largeTitleAppearance 对象分配给 standardAppearance scrollEdgeAppearance 导航栏的字段:

    self.navigationBar.standardAppearance = largeTitleAppearance // For large-navigationBar condition when it is collapsed
    self.navigationBar.scrollEdgeAppearance = largeTitleAppearance // For large-navigationBar condition when it is expanded
    

    Apple文档:

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

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


这对我有所帮助:https://sarunw.com/posts/uinavigationbar-changes-in-ios13/#going-back-to-old-style

答案 3 :(得分:3)

试试这段代码(Swift 4.0):

在viewDidLoad()

self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
if #available(iOS 11.0, *) {
    self.navigationController?.navigationBar.prefersLargeTitles = true
    self.navigationItem.largeTitleDisplayMode = .automatic
    self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
} else {
    //iOS <11.0
}
self.title = "Title"
self.navigationController?.navigationBar.barTintColor = UIColor(patternImage: #imageLiteral(resourceName: "nav_bg"))
self.navigationController?.navigationBar.isTranslucent = false

答案 4 :(得分:0)

在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 是可选的。当我在NavigationBar上“上下”一个图像时,我需要它。

答案 5 :(得分:0)

对oldrinmendez的回答捎带 - 该解决方案适用于水平渐变。

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

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

最后将更新功能添加到scrollViewDidScroll&amp; ViewDidApper:使用ViewDidAppear以便返回正确的导航栏高度

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

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

答案 6 :(得分:0)

更改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