【问题标题】:custom background image with large titles NavigationBar in iOS 11iOS 11 中带有大标题导航栏的自定义背景图像
【发布时间】:2018-02-22 02:58:53
【问题描述】:

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 仍然被渲染,但不知何故被隐藏了。仅当您开始滚动并出现“正常”导航栏时,背景图像才可见。在这种情况下,barTintColor 也被完全忽略。

【问题讨论】:

  • 嗨@alexkaessner。你找到问题的任何解决方案了吗..?
  • @OceanBlue 不! :/ 我刚刚检查了一下新的 NavBar。显示的大布局似乎有一个完全不同的视图,但这个视图没有改变。
  • 可以设置导航栏背景颜色或bartintcolor。但不幸的是我无法设置导航栏背景图像。这是ios 11的bug吗?你知道什么吗..?
  • @OceanBlue 我刚刚添加了更多分析信息,但这似乎是一个错误。我稍后会向 Apple 提交报告!
  • @Tulleb 一点也不。 Apple 将其标记为“与 33345493 重复”,但问题仍未解决。

标签: ios swift uinavigationbar ios11


【解决方案1】:

我遇到了同样的问题,解决了

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

【讨论】:

  • 我也试过这个,但我希望图像被拉伸而不是平铺。我的图像有渐变......或者有没有办法改变patternImage:的这些属性?
  • 好的,我现在已经测试过了,问题仍然是平铺。如果我旋转 iPhone,渐变太短并重复。 'horizo​​ntally: false' 也不能正常工作。它只是一个橙色的条形背景。
  • 救命稻草 :-)
  • 如果我们想拥有自己的没有图案或渐变颜色的背景图像怎么办。只是一个简单的图像,我想按原样显示它。你知道导航栏背景图片的大小应该是多少吗?
  • 这适用于常规标题大小和大标题大小,谢谢。
【解决方案2】:

我终于找到了解决办法!

编辑:适用于 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() 
    

    苹果文档:

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


  1. 配置它:

    largeTitleAppearance.configureWithOpaqueBackground()
    

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


  1. 设置背景图片:

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

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

    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 - 当任何可滚动内容的边缘到达导航栏的匹配边缘时使用的外观设置。


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

【讨论】:

  • 这是 iOS 13 中的修正解决方案。 UIColor(patternImage:) 解决方案只是 hack。
  • 太棒了,这是正确的解决方案!感谢您将其分享到这个旧帖子。太疯狂了,Apple 花了这么长时间才推出这个。
  • 顺便说一句,如果您需要更改背景图像的拉伸/定位,请查看backgroundImageContentMode
  • 也适用于 SwiftUI!
  • @HarryJ 哦,这就是我需要的。您需要使用 UIHostingController 还是有其他方法?
【解决方案3】:

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

【讨论】:

  • 感谢您的帖子,但这不是真正的解决方案。我还进行了更多测试和分析,似乎我必须坚持使用传统的导航栏(目前)。
  • 感谢您的出色回答。你知道导航栏背景图片的大小应该是多少(在你的例子中是navigationBarBackground)?
【解决方案4】:

试试这个代码(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

【讨论】:

    【解决方案5】:

    借鉴 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 & ViewDidApper添加更新函数:使用ViewDidAppear返回正确的导航栏高度

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

    【讨论】:

      【解决方案6】:

      在 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 上“卷曲”图像时需要它

      【讨论】:

        【解决方案7】:

        更改 barTint 对我不起作用,所以我更改了导航栏内的图层

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

        【讨论】:

        • 不,iOS 12 也一样
        猜你喜欢
        • 1970-01-01
        • 2018-04-14
        • 1970-01-01
        • 2020-02-10
        • 1970-01-01
        • 2018-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多