iOS13状态栏背景颜色与大文本模式下的导航栏不同

Posted

技术标签:

【中文标题】iOS13状态栏背景颜色与大文本模式下的导航栏不同【英文标题】:In iOS13 the status bar background colour is different from the navigation bar in large text mode 【发布时间】:2019-10-26 14:48:23 【问题描述】:

重现问题的前提条件:

    Xcode 11 beta + ios 13(2019 年 6 月 12 日之前的最新版本) 导航栏处于大文本模式 指定导航栏的颜色。

状态栏在真实设备中将保持为白色,位于绿色导航栏上方。

我尝试过的解决方案:

    恢复到iOS12就可以解决了,不过最终还是会遇到iOS13... 禁用大文本模式将解决它... 隐藏状态栏会修复它,但会导致状态文本与导航栏项目重叠。

有什么想法吗?感谢任何帮助。

【问题讨论】:

【参考方案1】:

这里不需要任何技巧或时髦。关键是定义所需的外观并在导航栏的standardAppearance 及其scrollEdgeAppearance 上设置此值。我的整个应用程序的基本导航控制器子类的 init 中有以下内容:

if #available(iOS 13.0, *) 
    let navBarAppearance = UINavigationBarAppearance()
    navBarAppearance.configureWithOpaqueBackground()
    navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
    navBarAppearance.backgroundColor = <insert your color here>
    navigationBar.standardAppearance = navBarAppearance
    navigationBar.scrollEdgeAppearance = navBarAppearance

【讨论】:

您的示例代码在 UIColor 上使用了自定义的 Theme 扩展,这使得它有点难以理解 当应用程序在后台运行时,当用户更改主题(例如 light -> dark )时,此方法存在一个问题。其他东西改变了它的颜色,但只有导航栏的色调颜色仍然存在。你可以很容易地看到这一点。只需在模拟器中运行应用程序并从设置应用程序中的开发人员设置更改外观。尝试覆盖 traitCollectionDidChange 并仍然出现错误。有什么想法吗? @CenoX ,我为您的问题找到了快速简便的解决方案。首先,在资产目录中创建新的颜色集。将外观从“无”更改为“任何、浅色、深色”。选择你想要的任何颜色。第二步是在代码中加载您的自定义 UIColor。使用 "let customColor = UIColor(named "CustomColor") ,将 name"CustomColor" 更改为您的资产名称。最后一步是将颜色分配给我们的条形背景。 我认为这是一个很好的解决方案@ShadeToD。我会尝试我的应用程序,谢谢。 如果您在 viewDidLoad() 之后执行此操作,请添加对 self.navigationController?.navigationBar.setNeedsLayout() 的调用【参考方案2】:

如果问题是您希望在显示大标题时为导航栏提供颜色,请使用新的 UINavigationBarAppearance 类。

let app = UINavigationBarAppearance()
app.backgroundColor = .blue
self.navigationController?.navigationBar.scrollEdgeAppearance = app

【讨论】:

你能帮我解决这个问题吗? “UINavigationBar”类型的值没有成员“scrollEdgeAppearance” 是的。 developer.apple.com/documentation/uikit/uinavigationbar/… 请记住这是我们正在谈论的 iOS 13。 老兄,你让我很开心,谢谢。【参考方案3】:

在 iOS 13 上,根据 Apple 人机界面指南,使用大标题的导航栏具有透明颜色。查看更多信息here:

在 iOS 13 及更高版本中,大标题导航栏默认不包含背景材质或阴影。此外,当人们开始滚动内容时,大标题会转换为标准标题

【讨论】:

那么,拥有大标题并想要自定义 bartint 颜色的解决方案是什么? @Reshad 使用 UINavigationBarAppearance 类。 @Reshad 在下面看到我的答案【参考方案4】:

通用代码

let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.backgroundColor = // your color
navBarAppearance.shadowImage = nil // line
navBarAppearance.shadowColor = nil // line
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).standardAppearance = navBarAppearance
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).scrollEdgeAppearance = navBarAppearance

【讨论】:

别忘了compactAppearance 最好使用这三个 UINavigationBar.appearance() 语句进行通用:UINavigationBar.appearance().standardAppearance = navBarAppearance UINavigationBar.appearance().compactAppearance = navBarAppearance UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance 不需要将compactAppearance设置为“如果不设置,将使用标准外观。”【参考方案5】:

我的导航栏扩展,iOS 13 Swift 5

extension UIViewController 
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) 
    if #available(iOS 13.0, *) 
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
        navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
        navBarAppearance.backgroundColor = backgoundColor

        navigationController?.navigationBar.standardAppearance = navBarAppearance
        navigationController?.navigationBar.compactAppearance = navBarAppearance
        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance

        navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
        navigationController?.navigationBar.isTranslucent = false
        navigationController?.navigationBar.tintColor = tintColor
        navigationItem.title = title

     else 
        // Fallback on earlier versions
        navigationController?.navigationBar.barTintColor = backgoundColor
        navigationController?.navigationBar.tintColor = tintColor
        navigationController?.navigationBar.isTranslucent = false
        navigationItem.title = title
    

使用方法:

configureNavigationBar(largeTitleColor: .yourColor, backgoundColor: .yourColor, tintColor: .yourColor, title: "YourTitle", preferredLargeTitle: true)

如果你想要轻量的内容,在 info.plist 中将基于 ViewController 的状态栏设置为 NO

如果您不希望 largeTitles 将其设置为 false

在 iOS 13 上测试,希望对您有所帮助:)

【讨论】:

非常感谢你,我希望我能给你更多这样的东西。 @Emon 谢谢!很高兴能帮到你:) 虽然这种方法有效,但最好不要为每个 UIViewController 实例使用 UINavigationBarAppearance 设置 NavigationBar 属性,因为 UINavigationBarAppearance 是共享的(有时只有一次出现) - 这可能导致在两个控制器都可见的情况下效果相当难看,例如当您执行(慢)向左滑动导航手势时。 @PavelLahoda 你的回答是正确的,但是新的操作系统会产生一些问题来显示大标题......正确的方法有时不起作用,最重要的是你很少在使用时使用滑动返回导航控制器,但在子控制器中自动创建的按钮......但是为了更安全,只需禁用滑动返回(这在 iOS 中是无用的并且不是很实用)。在所有情况下,感谢您的评论,它肯定会对以后阅读我们的人有用:) 如果您在应用程序中动态更改这些值,例如让用户选择自己的应用程序主题,那么您需要调用navigationController?.navigationBar.layoutSubviews() 以便立即应用更改。【参考方案6】:

Objective C 解决方案和 iOS 13

UINavigationBarAppearance* navBarAppearance = [self.navigationController.navigationBar standardAppearance];
        [navBarAppearance configureWithOpaqueBackground];
        navBarAppearance.titleTextAttributes = @NSForegroundColorAttributeName:TitleColor;
        navBarAppearance.largeTitleTextAttributes = @NSForegroundColorAttributeName: TitleColor;
        navBarAppearance.backgroundColor = TopColor;
        self.navigationController.navigationBar.standardAppearance = navBarAppearance;
        self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearance;

【讨论】:

【参考方案7】:

如果你想去掉导航栏下方的下划线

if #available(iOS 13.0, *) 
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        navBarAppearance.backgroundColor = <yourColor>
        navBarAppearance.backgroundImage = UIImage()
        navBarAppearance.shadowImage = UIImage()
        navBarAppearance.shadowColor = .clear
        self.navigationController?.navigationBar.standardAppearance = navBarAppearance
        self.navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
   
    

【讨论】:

【参考方案8】:

对于 iOS 13,我遇到了条形阴影线出现的问题。将 Bars 阴影图像设置为 nil 解决了这个问题。

之前

func configureNavigation() 
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.myColor,
                                                     .font: UIFont(name: "MyFont", size: 42)!]
        navBarAppearance.backgroundColor = .white
        navigationController?.navigationBar.isTranslucent = false
        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
    

之后

func configureNavigation() 
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.myColor,
                                                     .font: UIFont(name: "MyFont", size: 42)!]
        navBarAppearance.backgroundColor = .white
        navBarAppearance.shadowColor = nil
        navigationController?.navigationBar.isTranslucent = false
        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
    

【讨论】:

我很难看出之前和之后的区别 如果 SO 没有在浏览器中显示它们,那么我会尝试另一个屏幕或下载图像并查看它们,例如。 @stepheaw:在灰色白色边界上有一条很细很黑的线...【参考方案9】:

完全可行的代码:

 let navigationBarAppearace = UINavigationBar.appearance()
    navigationBarAppearace.tintColor = .tintColor
    navigationBarAppearace.barTintColor = .barTintColor
    navigationBarAppearace.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.tintColor]

if #available(iOS 13.0, *) 
  let navBarAppearance = UINavigationBarAppearance()
  navBarAppearance.configureWithOpaqueBackground()
  navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.tintColor]
  navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.tintColor]
  navBarAppearance.backgroundColor = <insert your color here>
  navigationBarAppearace.standardAppearance = navBarAppearance // have a look here ;)
  navigationBar.scrollEdgeAppearance = navBarAppearance

祝大家好运,和平!

【讨论】:

【参考方案10】:

感谢 Mike 和 Hans 的回答。我的案例是半透明状态栏和 alpha 0.5 的导航栏。 iOS13 看起来很复杂。以下是我的测试结果,如果您希望两者都透明,则可以使用。

if #available(iOS 13.0, *) 
                let navBarAppearance = UINavigationBarAppearance()
                // This only set top status bar as transparent, not the nav bar.
                navBarAppearance .configureWithTransparentBackground()
                // This set the color for both status bar and nav bar(alpha 1).
                navBarAppearance.backgroundColor = UIColor.red.withAlphaComponent(0.5)
                navigationController?.navigationBar.standardAppearance = navBarAppearance
                navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
                // Nav bar need sets to translucent for both nav bar and status bar to be translucent.
                navigationController?.navigationBar.isTranslucent = true
                // // Need to reset nav bar's color to make it clear to display navBarAppearance's color
                navigationController?.navigationBar.backgroundColor = UIColor.clear
                

【讨论】:

将外观背景颜色设置为红色然后使背景颜色清晰是没有意义的。【参考方案11】:

在更新我的一个应用程序以使其更兼容 iOS 13 时,我遇到了类似的问题。正如上面提到的Hans,大标题默认是透明的。如果您像我一样是 Storyboard 的重度用户,那么侧边栏中还有另一个设置很容易打开。

如果您单击故事板中的导航栏,通常默认选择Navigation Item,并且您不会获得任何自定义选项。选择其上方的Navigation Bar 选项,然后您可以在右侧的检查器中选择您想要的任何自定义背景颜色。

【讨论】:

执行此操作时,它与状态栏颜色不匹配。【参考方案12】:

我发现使用情节提要你必须伪造导航栏(假设你的绿色是不透明的,只适用于不透明的导航栏)。我发现最好的方法是创建一个适合安全区域插图的占位符视图(紫色),然后在导航栏(青色/蓝色)后面添加一个假视图,即剩余高度。适用于我的项目,但是是的,这有点麻烦。

编辑:这主要用于 LaunchScreen.storyboard,您不能使用自定义视图控制器类。

【讨论】:

【参考方案13】:

斯威夫特 5

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) 
    super.traitCollectionDidChange(previousTraitCollection)

    let userInterfaceStyle = traitCollection.userInterfaceStyle
    modeDetect(userInterfaceStyle: userInterfaceStyle)



override func viewDidAppear(_ animated: Bool) 
    navigationController?.navigationBar.barStyle = .black
    navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]


func modeDetect(userInterfaceStyle: UIUserInterfaceStyle) 
    switch userInterfaceStyle 
    case .light:
        navigationController?.navigationBar.barTintColor = .systemPink
    case .dark:
        navigationController?.navigationBar.barTintColor = .systemBackground
    default:
        break
    

【讨论】:

【参考方案14】:

使用适当的参数调用此函数。 此代码运行正常。

open func showNavigationBar(large: Bool,
                            animated: Bool,
                            isTransparabar: Bool,
                            titleColor: UIColor,
                            barBackGroundColor: UIColor,
                            fontSize: CGFloat) 

        navigationController?.navigationBar.barTintColor = barBackGroundColor
        navigationController?.navigationBar.backgroundColor = barBackGroundColor
        navigationController?.navigationBar.isTranslucent = true
        self.navigationController?.setNavigationBarHidden(false, animated: animated)
        if large 
            self.navigationController?.navigationBar.prefersLargeTitles = true
            if #available(iOS 13.0, *) 
                let appearance = UINavigationBarAppearance()
                appearance.backgroundColor = barBackGroundColor
                appearance.titleTextAttributes = [.foregroundColor: titleColor]
                appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]

                navigationController?.navigationBar.standardAppearance = appearance
                navigationController?.navigationBar.compactAppearance = appearance
                navigationController?.navigationBar.scrollEdgeAppearance = appearance
             else 
                self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
            
         else 
            self.navigationController?.navigationBar.prefersLargeTitles = false
            self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor!]
        
    

【讨论】:

【参考方案15】:

以下 Objective-C 代码使 iOS 13 导航栏的行为与我之前的版本一样:

    if (@available(iOS 13.0, *)) 
        // Setup iOS 13 navigation bar
        sharedSelector.navigationBar.scrollEdgeAppearance = sharedSelector.navigationBar.standardAppearance;
     else 
        // Fallback on earlier versions
    

【讨论】:

@deepak-verma 我应该提到我使用的是 Objective-C 而不是 Swift,所以语法对我来说是正确的。【参考方案16】:

我只是在故事板中打开半透明

【讨论】:

【参考方案17】:

Mike 的解决方案很棒。

我提供了另一种方法来更改适用于任何 iOS 版本的 UINavigationBar 颜色。

我们基本上将利用我们可以将图像设置为 UINavigationBar 的背景这一事实。

第一

添加扩展以从任何 UColor 生成 UIImage。请注意,您也可以稍后编写扩展程序,根据需要从十六进制或其他格式生成 UIColor。

extension UIColor 
    func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage 
        return UIGraphicsImageRenderer(size: size).image  rendererContext in
            self.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        
    


感谢@neoneye 为这个伟大的UIColor 扩展:)

第二次

现在我们开始谈正事:

private func setupNavigationBarAppearance(navBar: UINavigationBar) 
    navBar.isTranslucent = false
    let navBarColorImage = UIColor.blue.image()
    navBar.setBackgroundImage(navBarColorImage, for: .default)
    navBar.tintColor = UIColor.white

因为我们已经将不透明的彩色图像设置为背景,我们不需要检查 iOS 13

我希望这可以帮助一些人自定义他们的导航栏。

干杯!

【讨论】:

我刚刚通过 Xcode 11 实现了常规方法,但我喜欢你的想法。 :)

以上是关于iOS13状态栏背景颜色与大文本模式下的导航栏不同的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 7 上更改状态栏背景颜色和文本颜色?

如何在iOS 7上更改状态栏背景颜色和文本颜色? Warif Akhand Rishi

Xcode 13 - swift OS 15 中的导航栏和状态栏文本颜色变化

ios 实现自定义状态栏StatusBar 和 导航栏navigationBar 的状态和颜色

iOS 7 中 UIActivityViewControllers 的模态状态栏和导航栏文本颜色

iOS hidesBarsOnSwipe 状态栏背景颜色