How to remove the default Navigation Bar space in SwiftUI NavigationView
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 see that there is some white space above the List
.
What I want to accomplish is this:
I've tried using:
.navigationBarHidden(true)
but this did not make any noticeable changes.
I'm currently setting up my navigiationView like this:
NavigationView {
FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
.navigationBarHidden(true)
}
where FileBrowserView
is a view with a List
and FileCell
s defined like this:
List {
Section(header: Text("Root")) {
FileCell(name: "Test", fileType: "JPG",fileDesc: "Test number 1")
FileCell(name: "Test 2", fileType: "txt",fileDesc: "Test number 2")
FileCell(name: "test3", fileType: "fasta", fileDesc: "")
}
}
I do want to note that the ultimate goal here is that you will be able to click on these cells to navigate deeper into a file tree and thus should display a Back button on the bar on deeper navigation, but I do not want anything at the top as such during my initial view.
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.
View Modifiers made it easy:
//ViewModifiers.swift
struct HiddenNavigationBar: ViewModifier {
func body(content: Content) -> some View {
content
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
}
}
extension View {
func hiddenNavigationBarStyle() -> some View {
modifier( HiddenNavigationBar() )
}
}
Example:
import SwiftUI
struct MyView: View {
var body: some View {
NavigationView {
VStack {
Spacer()
HStack {
Spacer()
Text("Hello World!")
Spacer()
}
Spacer()
}
.padding()
.background(Color.green)
//remove the default Navigation Bar space:
.hiddenNavigationBarStyle()
}
}
}
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
If you set the title as inline for the View you want remove the space on, this doesn't need to be done on a view with a NavigationView, but the one navigated too.
.navigationBarTitle("", displayMode: .inline)
then simply change the Navigation bars appearance
init() {
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
UINavigationBar.appearance().shadowImage = UIImage()
}
on the view that holds the initial NavigationView.
If you want to change the Appearance from screen to screen change the appearance in the appropriate views
SwiftUI 2
There is a dedicated modifier to make the navigation bar take less space:
.navigationBarTitleDisplayMode(.inline)
EDIT
In some cases it may still be needed to add .navigationBarHidden(true)