How to remove the default Navigation Bar space in SwiftUI NavigiationView

后端 未结 15 2635
我在风中等你
我在风中等你 2020-11-29 20:00

I am new to SwiftUI (like most people) and trying to figure out how to remove some whitespace above a List that I embedded in a NavigationView

In this image, you can

相关标签:
15条回答
  • 2020-11-29 20:03

    The purpose of a NavigationView is to add the navigation bar on top of your view. In iOS, there are 2 kinds of navigation bars: large and standard.

    If you want no navigation bar:

    FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
    

    If you want a large navigation bar (generally used for your top-level views):

    NavigationView {
        FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
        .navigationBarTitle(Text("Title"))
    }
    

    If you want a standard (inline) navigation bar (generally used for sub-level views):

    NavigationView {
        FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
        .navigationBarTitle(Text("Title"), displayMode: .inline)
    }
    

    Hope this answer will help you.

    More information: Apple Documentation

    0 讨论(0)
  • 2020-11-29 20:04

    This is a bug present in SwiftUI (still as of Xcode 11.2.1). I wrote a ViewModifier to fix this, based on code from the existing answers:

    public struct NavigationBarHider: ViewModifier {
        @State var isHidden: Bool = false
    
        public func body(content: Content) -> some View {
            content
                .navigationBarTitle("")
                .navigationBarHidden(isHidden)
                .onAppear { self.isHidden = true }
        }
    }
    
    extension View {
        public func hideNavigationBar() -> some View {
            modifier(NavigationBarHider())
        }
    }
    
    0 讨论(0)
  • 2020-11-29 20:05

    Similar to the answer by @graycampbell but a little simpler:

    struct YourView: View {
    
        @State private var isNavigationBarHidden = true
    
        var body: some View {
            NavigationView {
                VStack {
                    Text("This is the master view")
                    NavigationLink("Details", destination: Text("These are the details"))
                }
                    .navigationBarHidden(isNavigationBarHidden)
                    .navigationBarTitle("Master")
                    .onAppear {
                        self.isNavigationBarHidden = true
                    }
                    .onDisappear {
                        self.isNavigationBarHidden = false
                    }
            }
        }
    }
    

    Setting the title is necessary since it is shown next to the back button in the views you navigate to.

    0 讨论(0)
  • 2020-11-29 20:06

    I have had a similar problem when working on an app where a TabView should be displayed once the user is logged in.

    As @graycampbell suggested in his comment, a TabView should not be embedded in a NavigationView, or else the "blank space" will appear, even when using .navigationBarHidden(true)

    I used a ZStack to hide the NavigationView. Note that for this simple example, I use @State and @Binding to manage the UI visibility, but you may want to use something more complex such as an environment object.

    struct ContentView: View {
    
        @State var isHidden = false
    
        var body: some View {
            
            ZStack {
                if isHidden {
                    DetailView(isHidden: self.$isHidden)
                } else {
                    NavigationView {
                        Button("Log in"){
                            self.isHidden.toggle()
                        }
                        .navigationBarTitle("Login Page")
                    }
                }
            }
        }
    }
    

    When we press the Log In button, the initial page disappears, and the DetailView is loaded. The Login Page reappears when we toggle the Log Out button

    struct DetailView: View {
        
        @Binding var isHidden: Bool
        
        var body: some View {
            TabView{
                NavigationView {
                    Button("Log out"){
                        self.isHidden.toggle()
                    }
                    .navigationBarTitle("Home")
                }
                .tabItem {
                    Image(systemName: "star")
                    Text("One")
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 20:08

    Try putting the NavigationView inside a GeometryReader.

    GeometryReader {
        NavigationView {
            Text("Hello World!")
        }
    }
    

    I’ve experienced weird behavior when the NavigationView was the root view.

    0 讨论(0)
  • 2020-11-29 20:09

    For some reason, SwiftUI requires that you also set .navigationBarTitle for .navigationBarHidden to work properly.

    NavigationView {
        FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
            .navigationBarTitle("")
            .navigationBarHidden(true)
    }
    

    Update

    As @Peacemoon pointed out in the comments, the navigation bar remains hidden as you navigate deeper in the navigation stack, regardless of whether or not you set navigationBarHidden to false in subsequent views. As I said in the comments, this is either a result of poor implementation on Apple's part or just dreadful documentation (who knows, maybe there is a "correct" way to accomplish this).

    Whatever the case, I came up with a workaround that seems to produce the original poster's desired results. I'm hesitant to recommend it because it seems unnecessarily hacky, but without any straightforward way of hiding and unhiding the navigation bar, this is the best I could do.

    This example uses three views - View1 has a hidden navigation bar, and View2 and View3 both have visible navigation bars with titles.

    struct View1: View {
        @State var isNavigationBarHidden: Bool = true
    
        var body: some View {
            NavigationView {
                ZStack {
                    Color.red
                    NavigationLink("View 2", destination: View2(isNavigationBarHidden: self.$isNavigationBarHidden))
                }
                .navigationBarTitle("Hidden Title")
                .navigationBarHidden(self.isNavigationBarHidden)
                .onAppear {
                    self.isNavigationBarHidden = true
                }
            }
        }
    }
    
    struct View2: View {
        @Binding var isNavigationBarHidden: Bool
    
        var body: some View {
            ZStack {
                Color.green
                NavigationLink("View 3", destination: View3())
            }
            .navigationBarTitle("Visible Title 1")
            .onAppear {
                self.isNavigationBarHidden = false
            }
        }
    }
    
    struct View3: View {
        var body: some View {
            Color.blue
                .navigationBarTitle("Visible Title 2")
        }
    }
    

    Setting navigationBarHidden to false on views deeper in the navigation stack doesn't seem to properly override the preference of the view that originally set navigationBarHidden to true, so the only workaround I could come up with was using a binding to change the preference of the original view when a new view is pushed onto the navigation stack.

    Like I said, this is a hacky solution, but without an official solution from Apple, this is the best that I've been able to come up with.

    0 讨论(0)
提交回复
热议问题