SwiftUI导航栏和状态栏 - 让它们颜色相同

11

我有一个新的应用程序,理想情况下,顶部将有一个坚实的深蓝色导航栏,延伸到状态栏后面。让它不透明并保持正确的蓝色是很麻烦的,但我终于找到了如何使其工作的方法,只需在包含NavigationView的View的init()中添加以下内容:

init() {
    UINavigationBar.appearance().barTintColor = UIColor(named: "primaryBlue")
    UINavigationBar.appearance().backgroundColor = UIColor(named: "primaryBlue")
    UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
    UINavigationBar.appearance().isOpaque = true
}

这将导致一个看起来像这样的导航栏。它是蓝色的,但状态栏仍然是白色的,带有黑色文本(我希望它是深蓝色的,带有白色文本)。

enter image description here

接下来,我知道我必须将状态栏的文本设置为“浅色内容”,并从Idiqual 这里找到了一个好的解决方案,但这只是改变了栏的颜色“主题”,似乎没有办法使用此方法更改背景颜色。实施后,我现在有一个准备好在深色背景上显示浅色文本的状态栏,但我无法弄清如何使NavigationView的深蓝色背景延伸到状态栏的顶部。所以我现在只能得到这个:

enter image description here

我尝试了几种方法,例如在不同位置添加.edgesIgnoringSafeArea(.top),包括NavigationView的闭合括号和父视图中的TabView,但都没有效果。我是否漏掉了一些简单的东西?如何将NavigationBar的颜色延伸到屏幕顶部?这是我的Nav视图代码。这个结构体叫做“FetchFrontPageArticles”:

var body: some View {
    NavigationView {
        VStack {
            List(self.fetcher.articles) { article in
                ...
            }.navigationBarTitle("", displayMode: .inline)
            .navigationBarItems(
                leading: Text(""),
                trailing: NavProfile()
            )
        }
    }
}

"

“FetchFrontPageArticles”从此处显示的父TabView中加载:

"
TabView(selection: $selection){
        FetchFrontPageArticles()
            .tabItem {
                VStack {
                    Image("house")
                    Text("Home")
                }
            }
            .tag(0)
        Text("Second View")
            .tabItem {
                VStack {
                    Image("list.dash")
                    Text("Browse")
                }
            }
            .tag(1)
        ...
    }
    .accentColor(Color("primaryYellow"))

我在解决这个问题上遇到了困难,但看起来应该很简单。请帮忙!
更新:根据Kyle下面的答案,我已经尝试过这种方法。这是实现NavConfigurator后我的导航栏的屏幕截图(注意条形图看起来更浅的蓝色,因为透明度效果发挥了作用):

enter image description here


自发布以来,我发现只有在视图中有列表时才会出现这种情况。如果我删除列表,则我的应用程序将尊重导航栏的.edgestIgnoreSafeArea修饰符。但是,一旦添加了列表,您的状态栏就会变为白色,因为这是列表的背景颜色。您可以更改UITableView的背景颜色,但是当您这样做并滚动时,您仍然可以看到单个行通过状态栏,就好像它是透明的。 - eResourcesInc
4个回答

22

当我开始使用SwiftUI编码时,我遇到了同样的问题,经过大量研究,我找到了解决方案。

将下面的代码放在SceneDelegate类中。

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {        
    let newAppearance = UINavigationBarAppearance()
    newAppearance.configureWithOpaqueBackground()
    newAppearance.backgroundColor = .black
    newAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]

    UINavigationBar.appearance().standardAppearance = newAppearance

    //Other code for displaying the first screen
}

UINavigationBarAppearance类用于更改导航栏的外观,它从iOS 13开始可用。

上述代码将更改所有控制器的导航栏样式。


2
这段代码实际上做到了其他我在互联网上找到的代码没有能够达到的效果。非常感激。 - eResourcesInc
1
当导航栏存在时,此答案能够正常工作。如果在一个视图中隐藏了该栏,则状态栏会失去背景色(变为透明)。 - Alan Steiman
我的应用程序在将此代码放入场景函数中时崩溃。***终止应用程序,原因是未捕获的异常'NSInvalidArgumentException',原因:'-[__SwiftValue set]:向实例0x2816809c0发送了无法识别的选择器' - Zhou Haibo
UINavigationBarAppearance 在 iOS13 中引入,非常好用。除了 UITabBar.standardAppearance 之外,您可能还需要设置 UITabBar.scrollEdgeAppearance - Jason Moore

7
以下是我的翻译:

以下方法适用:

创建一个UINavigationController的扩展,它将更改以下内容:

  • navigationbar background color
  • statusbar background color
  • navigationbar title color

    import UIKit
    
    extension UINavigationController {
        override open func viewDidLoad() {
            super.viewDidLoad()
    
            let appearance = UINavigationBarAppearance()
            //background color of the navigation and status bar
            appearance.backgroundColor = .black
            //color when the title is large
            appearance.largeTitleTextAttributes.updateValue(UIColor.white, forKey: NSAttributedString.Key.foregroundColor)
            //color when the title is small
            appearance.titleTextAttributes.updateValue(UIColor.white, forKey: NSAttributedString.Key.foregroundColor)
    
            // change the background- and title foregroundcolor for navigationbar
            navigationBar.standardAppearance = appearance
            navigationBar.scrollEdgeAppearance = appearance
            navigationBar.compactAppearance = appearance
            // change color of navigationbar items
            navigationBar.tintColor = UIColor.white
        }
    }
    

然而这不会改变状态栏的前景色。为了实现此目的,我们需要执行以下操作:

导入SwiftUI

class HostingController<Content> : UIHostingController<Content> where Content : View {
    @objc override dynamic open var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
}

然后在我们的场景委托中,

我们需要替换

window.rootViewController = UIHostingController(rootView: contentView)

使用
window.rootViewController = HostingController(rootView: contentView)

navigationBar.scrollEdgeAppearance 对我有用。 - Joony

0

我在这个问题上纠结了大约一个小时,最后发现如果你正在使用TabView,则需要将edgesIgnoringSafeArea添加到TabView而不是选项卡中的视图。

TabView {
   ViewA().tabItem.....

}.edgesIgnoringSafeArea(.top)

希望能有所帮助


如果我这样做,NavigationView 将会被缺口遮挡。 - Joris Mans
在我的情况下,我使用TabView作为应用程序的基本视图,并且导航视图位于TabView内部。我不确定您的navigationView是否在TabView中。 - cookiezby
1
当你的TabView是应用程序的基础,而ViewA()是一个导航视图时,在上面的示例中,你应该向View()添加.edgesIgnoringSafeArea(.top) - JacobF

-1
尝试使用 UIViewControllerRepresentative:
NavigationView {
    VStack {

         // your stuff

    }
    .accentColor(.white)
    .background(NavConfigurator { nav in
                nav.navigationBar.barTintColor = UIColor(named: "primaryBlue")
                nav.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.white]
    })
}

编辑:忘记代表性代码:

import SwiftUI

struct NavConfigurator: UIViewControllerRepresentable {

    var configure: (UINavigationController) -> Void = { _ in }

    func makeUIViewController(context: UIViewControllerRepresentableContext<NavConfigurator>) -> UIViewController {
        UIViewController()
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavConfigurator>) {
        if let nc = uiViewController.navigationController {
            self.configure(nc)
        }
    }

}

什么是 NavConfigurator - LuLuGaGa
我已经尝试过这个方法,但结果相同,只是我的状态栏在这种情况下甚至不是不透明的。我还尝试了在视频中看到的ZStack方法,例如:https://www.youtube.com/watch?v=1pK1yZlzeTw。但由于某种原因,zstack颜色从未显示在我的状态栏上方。我正在编辑我的答案以展示当我使用这种方法时它是什么样子的。 - eResourcesInc

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