简体   繁体   中英

SwiftUI Navigation Bar and Status Bar - Make them same color

I have a new app that ideally will have a solid dark blue navigation bar at the top that extends up behind the status bar. It was a pain to make this opaque and the correct color of blue, but I finally figured out how to make it work by putting the following in the init() of my View that contains the NavigationView:

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

This results in a navigation bar that looks like this. It's blue, but the status bar is still white with black text (I want it to be dark blue with white text).

在此处输入图片说明

Next, I knew that I had to make the text of the status bar "light content", and found a good solution from Idiqual here , but this simply changes the color "theme" of the bar, and there doesn't appear to be a way to change the background color using this method. After implementation, I now have a status bar that is ready to show light text on a dark background, but I'm unable to figure out how to get the dark blue background of the NavigationView to extend to the top of the status bar. So what I'm left with is this:

在此处输入图片说明

I've tried several things, such as adding .edgesIgnoringSafeArea(.top) to several different places, including the closing bracket of the NavigationView and also the TabView that I have in the parent view, but nothing works. Am I missing something simple? How do I extend the NavigationBar's color to the top of the screen? Here is the code for my Nav view. This struct is called "FetchFrontPageArticles":

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

"FetchFrontPageArticles" is loaded from the parent TabView shown here:

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"))

I'm pretty stuck trying to resolve this, and it seems like it should be simple. Please help!

UPDATE: Per Kyle's answer below, I've already tried this approach. Here is a screenshot of my nav bar after implementing the NavConfigurator (notice the bar looks lighter blue, because the transparency effect comes into play):

在此处输入图片说明

When I started coding with SwiftUI , I faced the same issue and after so much research I found the solution.

Put the below code in the SceneDelegate class.

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 class is used for changing appearance of the navigation bar and it is available from iOS 13.

The above code will change the navigation bar style of all the controllers.

The following works for me:

create an extension for UINavigationController which will change the following:

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

however this will not change the statusbar foreground color. for that we need to do the following:

import SwiftUI

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

and then in our scenedelegate

we need to replace

window.rootViewController = UIHostingController(rootView: contentView)

with

window.rootViewController = HostingController(rootView: contentView)

I have struggled on this problem for about one hour, finally I find that if you are using TabView, you need to add the edgesIgnoringSafeArea to TabView rather than the view in the tab.

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

}.edgesIgnoringSafeArea(.top)

hope it helps

Try using a UIViewControllerRepresentative :

NavigationView {
    VStack {

         // your stuff

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

Edit: Forgot representative code:

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

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM