Froig
Froig

Reputation: 73

SwiftUI - Navigation title background becomes transparent when VStack is visible

I'm running into an issue with the navigation title header in SwiftUI. It's a combination of a couple of things, as far as I can tell...

The main problem is that I'm trying to change the default background color of a view that contains a list. But when I use the tag .background(), the navigation title background becomes transparent. This only happens when there is a VStack on the view.

I have a simplify example code that shows the problem I'm facing:

ContentView:

import SwiftUI

struct ContentView: View {
    @State var showButton: Bool

    var body: some View {
        VStack {
            NavigationStack {
                NavigationLink(
                    destination: SecondView(showButton: showButton),
                    label: {
                        Text("Take me to second view")
                    })
                Toggle("VStack Visibile", isOn: $showButton)
                    .padding()
            }
        }
    }
}

SecondView:

import SwiftUI

struct SecondView: View {
    @State private var isButtonVisible: Bool = false
    @State var showButton: Bool = true
    
    var body: some View {
        VStack {
            List(0..<10) { _ in
                Text("Hello World")
            }
            if showButton {
                button
            }
        }
        .navigationTitle("This is a title")
        .background(Color(.systemCyan))
    }
    
    var button: some View {
        Text("Something")
    }
}

Please see below the resulting problem:

enter image description here

Upvotes: 0

Views: 1232

Answers (2)

user1046037
user1046037

Reputation: 17685

Issues / Suggestions:

ContentView

  • Have the NavigationStack outside the VStack

SecondView

  • Don't embed List inside a VStack
  • List is special and has special characteristics
  • Don't initialise @State property from outside, pass a binding instead

Code:

ContentView:

struct ContentView: View {
    @State var showButton = true
    
    var body: some View {
        NavigationStack {
            VStack {
                NavigationLink(
                    destination: SecondView(showButton: $showButton),
                    label: {
                        Text("Take me to second view")
                    })
                Toggle("VStack Visibile", isOn: $showButton)
                    .padding()
            }
        }
    }
}

SecondView

struct SecondView: View {
    @State private var isButtonVisible: Bool = false
    @Binding var showButton: Bool
    
    var body: some View {
        List {
            ForEach(0..<100) { _ in
                Text("Hello World")
            }
        }
        .safeAreaInset(edge: .bottom) {
            if showButton {
                HStack {
                    Spacer()
                    button
                    Spacer()
                }
                //I have added transparency, you can make it opaque if you want
                .background(.cyan.opacity(0.8))
            }
        }
    }
    
    var button: some View {
        Text("Something")
    }
}

Bottom Overlay

Upvotes: 3

Slappy
Slappy

Reputation: 95

Try this if you don't want your list go under nav bar.

struct SecondView: View {
    @State private var isButtonVisible: Bool = false
    @State var showButton: Bool = true
    
    var body: some View {
        VStack {
            List(0..<10) { _ in
                Text("Hello World")
            }
            .padding(.top, 1)
            if showButton {
                button
            }
        }
        .background(Color(.systemCyan))
        .navigationTitle("This is a title")
    }
    
    var button: some View {
        Text("Something")
    }
}

Upvotes: 0

Related Questions