iOS 15 导航栏透明化

165
我的iOS应用程序使用storyboard来设计用户界面,并使用自定义色调作为导航栏背景颜色。
我在Xcode 13 beta 5上测试了我的应用程序,发现导航栏是“白色的”,导航栏上的文本不可见。
在苹果开发者论坛https://developer.apple.com/forums/thread/682420中指出:“在iOS 15中,UIKit扩展了scrollEdgeAppearance的使用,该属性默认产生透明背景,适用于所有导航栏。” 要恢复旧的外观,您必须采用新的UINavigationBar外观API。
我添加了上述代码(来自上面的链接)到App Delegate的“application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions”方法中。
        if #available(iOS 13, *) {
            let navigationController = UINavigationController(navigationBarClass: nil, toolbarClass: nil)
            let navigationBar = navigationController.navigationBar
            let appearance = UINavigationBarAppearance()
            appearance.configureWithOpaqueBackground()
            appearance.backgroundColor = UIColor(red: 0.0/255.0, green: 125/255.0, blue: 0.0/255.0, alpha: 1.0)
            navigationBar.standardAppearance = appearance;
            navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance
            navigationBar.isTranslucent = false
        }

这并没有解决问题。我仍然在导航栏的storyboard编辑器中设置了自定义色调。我是需要删除自定义色调还是我的外观API实现有误?


你在代码片段中创建了一个新的UINavigationController实例。你打算用这个实例做什么?只是猜测:我认为你正在寻找类似于UINavigationBar.appearance()的东西,但老实说,我不熟悉新的iOS 15 API。 - Teetz
https://developer.apple.com/forums/thread/682420 - Trenton McKinney
19个回答

164

要使用自己的颜色方案,请使用以下内容:

Swift

// White non-transucent navigatio bar, supports dark appearance
if #available(iOS 15, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
}

Objective-C

if (@available(iOS 15.0, *)) {
    UINavigationBarAppearance *navBarAppearance = [[UINavigationBarAppearance alloc] init];
    navBarAppearance.backgroundColor = [UIColor redColor];
    [navBarAppearance configureWithOpaqueBackground];
    [UINavigationBar appearance].standardAppearance = navBarAppearance;
    [UINavigationBar appearance].scrollEdgeAppearance = navBarAppearance;
}

要获取默认的半透明效果,就像iOS 15之前一样,默认设置scrollEdgeAppearance即可:

Swift

if #available(iOS 15, *) {
    UINavigationBar.appearance().scrollEdgeAppearance = UINavigationBarAppearance()
}

Objective-C

if (@available(iOS 15.0, *)) {
    [UINavigationBar appearance].scrollEdgeAppearance = [[UINavigationBarAppearance alloc] init]; 
}

7
谢谢。不确定为什么其他答案有这么多赞,但这个提供了正确的“Xcode 13之前”的导航栏行为。如果需要的话,您还可以使用configureWithDefaultBackground()来保留旧的透明效果。 - Adam Kaump
5
我明白了。为了将不同颜色应用于多个navigationController,我给self.navigationController.navigationBar的standardAppearancescrollEdgeAppearance赋值,而不是修改UINavigationBar.appearance()。我确实在我的appDelegate中修改了UINavigationBar.appearance(),但那只是为了设置一般默认值。 - Jargen89
希望能够在使用Xcode 12.5.1的同时解决这个问题,这将是非常好的。 :/ - nodebase
2
谢谢你的回答。我认为它很好用,但你应该编辑一下,把新的backgroundColor放在"configureWithOpaqueBackground"后面。否则,configure调用会将颜色重置为系统默认值。 - Frank Hartmann
非常感谢这个提示,我也用它来处理 [UITabBar appearance]。 - Pinchus G.
显示剩余5条评论

93

不需要更改任何故事板内容。 以下是最终在应用程序委托中添加的解决方案 application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:

//Fix Nav Bar tint issue in iOS 15.0 or later - is transparent w/o code below
if #available(iOS 15, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    appearance.backgroundColor = UIColor(red: 0.0/255.0, green: 125/255.0, blue: 0.0/255.0, alpha: 1.0)
    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
}

请注意,如果未指定标题文本属性,则标题文本默认为黑色,因此需要将标题文本属性设置为“white”。

还要注意,这仅适用于iOS 15.0或更高版本。对于早期版本,由于故事板导航栏自定义色调是默认行为,因此无法使用该方法。


6
我认为你应该将 navigationBar.standardAppearance = appearance; 替换为 UINavigationBar.appearance().standardAppearance = appearance - IluSioN
是的,你说得对 - 发帖后我注意到了这一点。 - G. Steve
已更新上方内容以反映@IluSioN的更正。 - G. Steve
这段代码应该放在哪里? - Mahmudur Rahman
我在App Delegate中添加了application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions - G. Steve
显示剩余4条评论

44

如果有人需要 Objective C 版本的 G. Steve 的答案

if (@available(iOS 15, *)){
        UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
        [appearance configureWithOpaqueBackground];
        appearance.titleTextAttributes = @{NSForegroundColorAttributeName : UIColor.whiteColor};
        appearance.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:125/255.0 blue:0.0/255.0 alpha:1.0];
        [UINavigationBar appearance].standardAppearance = appearance;
        [UINavigationBar appearance].scrollEdgeAppearance = appearance;
    }

31

在界面构建器中(Xcode 13 - iOS 13及以上版本已测试),我的排序得到了解决,并且不需要检查iOS 15的可用性(即@available)。

  1. 选择导航栏的标准和滚动边缘外观。

输入图像描述

  1. 为两个外观选择类似的设置

输入图像描述

输入图像描述

祝你好运!


这个回答非常有用。但是你能分享一下如何在界面构建器中更改标题颜色和标题字体吗?我尝试过了,但没有成功。谢谢。 - iPhone
您需要使用您的偏好设置来设置 titleTextAttributes 属性。 - Kumar C
1
请注意,此功能仅适用于目标 iOS 13.0 或更高版本的应用程序。如果设置支持旧版 iOS 版本,则会出现错误“Main.storyboard: error: Class Unavailable: Navigation Bar Appearances before iOS 13.0”。 - Martijn

17

在我的情况下,当我更新到xcode13和iOS15时,我发现navigationBar和tabBar变成了透明的。我的viewController嵌入在UINavigationController中。

enter image description here

navigationController?.view.backgroundColor = .yourColor

颜色一旦设定,一切就好了

enter image description here


1
这是对我来说最好的答案。 - Zou
这段代码应该放在哪里? - Mahmudur Rahman
@MahmudurRahman 根据你的业务逻辑,在任何可以获取到navigationController的地方。 - wlixcc
你甚至可以在检查器中完成这个。 - f.b.

11

这段代码可以放在任何地方,不仅仅是在应用程序委托中,以解决iOS15上的问题:

if (@available(iOS 15, *)){
        UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
        [appearance configureWithOpaqueBackground];
        appearance.titleTextAttributes = @{NSForegroundColorAttributeName : UIColor.blackColor};
        appearance.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:125/255.0 blue:0.0/255.0 alpha:1.0];
        self.navigationController.navigationBar.standardAppearance = appearance;
        self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
    }

仅提供代码作为答案并不是良好的做法。请考虑解释这个答案是如何回答问题的 - DevWithZachary

8

Xcode 13+

iOS 15中,UIKit将scrollEdgeAppearance的使用范围扩展到了所有导航栏。默认情况下,该属性会生成透明背景,并且由滚动视图在导航栏后面滚动内容来控制背景。

如果要恢复旧的外观,您必须采用新的UINavigationBarAppearance外观API,并移除现有的自定义设置,然后像这样操作:

    let appearance = UINavigationBarAppearance()
    appearance.backgroundColor = <your tint color>
    navigationBar.standardAppearance = appearance
    navigationBar.scrollEdgeAppearance = appearance

您还可以使用外观代理来执行上述代码,但将最后一行替换为 navigationBar.appearance().scrollEdgeAppearance = appearance


5

我为支持iOS 15和iOS 12创建了这个扩展,仅在需要的位置更改导航栏背景(色调)和标题颜色,而不是整个应用程序。

extension UINavigationBar {
  func update(backroundColor: UIColor? = nil, titleColor: UIColor? = nil) {
    if #available(iOS 15, *) {
      let appearance = UINavigationBarAppearance()
      appearance.configureWithOpaqueBackground()
      if let backroundColor = backroundColor {
        appearance.backgroundColor = backroundColor
      }
      if let titleColor = titleColor {
        appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
      }
      standardAppearance = appearance
      scrollEdgeAppearance = appearance
    } else {
      barStyle = .blackTranslucent
      if let backroundColor = backroundColor {
        barTintColor = backroundColor
      }
      if let titleColor = titleColor {
        titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
      }
    }
  }
}

并且在需要的地方使用它(在我的情况下,是 UIViewController 的 UI 配置)像这样

  func configureNavigationController() {
    navigationController?.navigationBar.update(backroundColor: .blue, titleColor: .white)
  }

1
它可以改变状态栏的颜色! - Rashad
同样的问题在这里。 - bhavik

3
任何需要Objective-C解决方案的人,请尝试以下代码:

若要在iOS应用中添加动画效果,请按照以下步骤进行操作:

if (@available(iOS 15.0, *)) {
        UINavigationBarAppearance *navBarAppearance = [[UINavigationBarAppearance alloc] init];
        [navBarAppearance configureWithOpaqueBackground];
        navBarAppearance.backgroundColor = YOUR_COLOR;
        [navBarAppearance setTitleTextAttributes:
                @{NSForegroundColorAttributeName:[UIColor whiteColor]}];

        self.navigationController.navigationBar.standardAppearance = navBarAppearance;
        self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearance;
    }

这已经在其他答案中提到,例如这个这个。当回答已有答案的旧问题时,请确保您提供的是新颖的解决方案或比现有答案更好的解释。 - Eric Aya
@EricAya 嘿,我确实在分享答案之前尝试过寻找,但是我没有找到 Objective-c 的解决方案。 - Mahendra Liya
我链接的两个答案都是Objective-C。也许你没有注意到,但问题的标签是Swift。 - Eric Aya

3

我尝试了多种方法,但以下代码像魔法一样成功还原了之前的版本。

    if #available(iOS 15, *) {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithOpaqueBackground()
        appearance.backgroundColor = .white
        UINavigationBar.appearance().standardAppearance = appearance
        UINavigationBar.appearance().scrollEdgeAppearance = appearance
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接