简体   繁体   中英

How change background color if using NavigationView in SwiftUI?

I want to change background color for full screen. I am using NavigationView , and I want to set Gray color for background (not default white)

struct ContentView : View {
    var body: some View {
        NavigationView {
            ScrollView {
                Text("Example")
            }
            .navigationBarTitle("titl")
        }
    }
}

Setting .background(Color.red) does not work in any place.

preview

If you just embed your content in the NavigationView within a ZStack you should be able to throw the color in underneath your main content.

struct ContentView : View {
    var body: some View {
        NavigationView {
            ZStack {
                Color.red.edgesIgnoringSafeArea(.all)
                ScrollView {
                    Text("Example")
                }
                .navigationBarTitle("title")
            }
        }
    }
}

Adding to Mattis Schulte's answer, one of the side effects I've encountered is that the status bar will not inherit the background color.

However when you scroll a List (for example) up toward the top of the view and iOS switches to an inline title view (with the centered NavigationBarTitle) it does color in the status bar area leaving a fairly undesirable user experience.

The workaround I was able to use is:

import SwiftUI

let coloredNavAppearance = UINavigationBarAppearance()
   
struct ListView: View {

    init() {
        coloredNavAppearance.configureWithOpaqueBackground()
        coloredNavAppearance.backgroundColor = .systemBlue
        coloredNavAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        coloredNavAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
               
        UINavigationBar.appearance().standardAppearance = coloredNavAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = coloredNavAppearance

    }

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("General")) {
                    HStack {
                        Text("ListView #1")
                        Spacer()
                        Text("data")
                            .multilineTextAlignment(.trailing)
                    }
                    HStack {
                        Text("ListView #2")
                        Spacer()
                        Text("data")
                            .multilineTextAlignment(.trailing)
                    }
                }

            }
            .navigationBarTitle("NavBar Title")
        }
    }
}


struct ListView_Previews: PreviewProvider {
    static var previews: some View {
        ListView()
    }
}

Hope this helps someone else. Credit to https://sarunw.com/posts/uinavigationbar-changes-in-ios13/

A newest solution is having an extension for UINavigationController , as below:

extension UINavigationController {
    override open func viewDidLoad() {
        super.viewDidLoad()

    let standard = UINavigationBarAppearance()
    standard.backgroundColor = .red //When you scroll or you have title (small one)

    let compact = UINavigationBarAppearance()
    compact.backgroundColor = .green //compact-height

    let scrollEdge = UINavigationBarAppearance()
    scrollEdge.backgroundColor = .blue //When you have large title

    navigationBar.standardAppearance = standard
    navigationBar.compactAppearance = compact
    navigationBar.scrollEdgeAppearance = scrollEdge
 }
}

OR, The old one:

Inside your struct initializer change UITableView color, as below:

struct ContentView : View {
init() {
    UITableView.appearance().backgroundColor = .red
    }
var body: some View {
    NavigationView {
        ScrollView {
            Text("Example")
        }
        .navigationBarTitle("title")
    }
  }
}

Just add this to the initializer of your code UIScrollView.appearance().backgroundColor = UIColor.red . But unfortunately, this solution has many side effects.

One little hack that you can do is add a text view that doesnt have any text in it and add the background color to what you want, something like the following:

Text(" ")
    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
    .background(Color.red)
    .edgesIgnoringSafeArea(.all)

Ok I just tried omar's solution, and unfortunately it doesn't work if there are any other views in the stack.

So the best answer I've seen for now that actually changes the underlying background color of the NavigationView (in OP's original question) is just setting the background color on the UIView appearance, as eluded to in this answer :

UIView.appearance().backgroundColor = UIColor.red

Here is my solution as none of the others worked in my case so I thought I would share..

So for the Navigation header bar colour, add an initialiser like this:

struct ContentView: View {
    init() {
        UINavigationBar.appearance().backgroundColor = .red
    }
    var body: some View {
        NavigationView {
            ScrollView {
                ...
            }
        }
    }
}

And then for editing the ScrollView background color, you can do something like this: I have done for ListView but you can do it for ScrollView.

struct ListBackgroundColor: ViewModifier {

    let color: UIColor

    func body(content: Content) -> some View {
        content
            .onAppear() {
                UITableView.appearance().backgroundColor = self.color
                //(Optional) Edit colour of cell background
                UITableViewCell.appearance().backgroundColor = self.color
            }
    }
}   

extension View {
    func listBackgroundColor(color: UIColor) -> some View {
        ModifiedContent(content: self, modifier: ListBackgroundColor(color: color))
    }

}

UI Example https://imgur.com/a/TQ9c5Sc

The new way to do it

extension UINavigationController {

    open override func viewDidLoad() {
        super.viewDidLoad()

        let standardAppearance = UINavigationBarAppearance()
        standardAppearance.backgroundColor = .blue
        standardAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        standardAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        navigationBar.standardAppearance = standardAppearance
        navigationBar.compactAppearance = standardAppearance
        navigationBar.scrollEdgeAppearance = standardAppearance

    }}

If you need separate styles for compactAppearance , scrollEdgeAppearance

extension UINavigationController {

open override func viewDidLoad() {
    super.viewDidLoad()

    let standardAppearance = UINavigationBarAppearance()
    standardAppearance.backgroundColor = .blue
    standardAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    standardAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]


    let compactAppearance = UINavigationBarAppearance()
    compactAppearance.backgroundColor = .red


    let scrollEdgeAppearance = UINavigationBarAppearance()
    scrollEdgeAppearance.backgroundColor = .yellow


    navigationBar.standardAppearance = standardAppearance
    navigationBar.compactAppearance = compactAppearance
    navigationBar.scrollEdgeAppearance = scrollEdgeAppearance

}}

For more read

it's quite complicated to change bg color for NavigationView and keep it working properly like minification / magnification during content scrolling and also keeping safe areas

NavigationView-color-customisation on github here i posted common problems and solutions about color customisation in SwiftUI app

also if you really want to change bg color in ALL navgiationViews, prev comment's first part about Extension on UINavigationController looks good

NavigationView in SwiftUI and UINavigationBar in UIKit are just as cumbersome, and I have a third-party open source solution for iOS system navigation bars that I hope will help you solve the problem.

Git repo: NXNavigationExtension

Change NavigationView color:

struct ContentView: View {
    
    var body: some View {
        NavigationView {
            NavigationLink {
                Text("Pop")
                    .padding()
                    .useNXNavigationView(onPrepareConfiguration: { configuration in
                        // Page2
                        configuration.navigationBarAppearance.backgroundColor = .green
                    })
            } label: {
                Text("Push")
                    .padding()
                    .useNXNavigationView(onPrepareConfiguration: { configuration in
                        // Page1
                        configuration.navigationBarAppearance.backgroundColor = .red
                    })
            }
        }
        .navigationViewStyle(.stack)
    }
    
}

📝 example

For the nav bar in iOS 16 +

.toolbarBackground(.red, for: .navigationBar)

for iOS 14 and less

UINavigationBar.appearance().barTintColor = UIColor.red

for iOS 15

NavigationView {
            ZStack(alignment: .top) {
                GeometryReader { reader in
                    Color.red
                        .frame(height: reader.safeAreaInsets.top, alignment: .top)
                        .ignoresSafeArea()
                }

                // your content view
            }

It's hard to get a "one size fits all solution" but in general it's possible to do this by introspecting the "hidden" view controller and setting it's background color. Best to use SwiftUI-Introspect for this. In your case:

struct ContentView : View {
    var body: some View {
        NavigationView {
            ScrollView {
                Text("Example")
            }
            .navigationBarTitle("titl")
            .introspectViewController { vc in
                vc.view.backgroundColor = .clear
            }
        }
    }
}

It's possible that your view composition is different. To find the correct view debug your view hierarchy in Xcode and set the backgroundColor on it. This could be via vc.parent or vc.parent.subviews or elsewhere in your view hierarchy.

Caveat: In my case I needed to use the modifier on my NavigationLink destination.

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