Reputation: 738
I have a ContentView
containing a NavigationView
that leads to a DestinationView
. I want to hide the navigation bar in the ContentView
, but show it in the DestinationView
. To hide it in the ContentView
I set navigationBarHidden
to true
and give navigationBarTitle
an empty string.
In the DestinationView
I set navigationBarHidden
to false and give it the title "DestinationView".
If I run the project and tap on the NavigationLink
, the DestinationView
shows the NavigationBar
but quickly hides it after the view appeared. Can anybody help me with this?
struct ContentView: View {
var body: some View {
NavigationView {
ZStack {
Color.red.frame(maxWidth: .infinity, maxHeight: .infinity)
NavigationLink(destination: DestinationView()) {
ZStack {
Color.green.frame(width: 200, height: 200)
Text("Tap me")
}
}
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
struct DestinationView: View {
var body: some View {
List {
Text("1")
Text("2")
}
.navigationBarTitle("DestinationView")
.navigationBarHidden(false)
}
}
Upvotes: 7
Views: 3820
Reputation: 318
I run this code on an iOS 14 Simulator and the navigation bar did not hide, so I assume this might be an issue with iOS 13. I had a similar problem and my code which resulted in nav bar disappearing on iOS 13.5 Simulator worked fine on iOS 14.4 Simulator.
Upvotes: 0
Reputation: 237
There ist actually a really simple solution to this problem. After many tries I figured it, that you have to add the .navigationBarHidden(false)
directly to the destination view inside the NavigationLink
like this:
struct ContentView: View {
var body: some View {
NavigationView {
ZStack {
Color.red.frame(maxWidth: .infinity, maxHeight: .infinity)
NavigationLink(destination: DestinationView()
.navigationBarHidden(false)) {
ZStack {
Color.green.frame(width: 200, height: 200)
Text("Tap me")
}
}
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
struct DestinationView: View {
var body: some View {
List {
Text("1")
Text("2")
}
.navigationBarTitle("DestinationView")
.navigationBarHidden(false)
}
}
It will work like desired, and won't disappear after showing up.
Upvotes: 0
Reputation: 3205
For me passing a binding around through the view hierarchy wasn't optimal, adding the state to an environment var was preferable.
class SceneState: ObservableObject {
@Published var isNavigationBarHidden = true
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
...
var sceneState = SceneState()
...
let contentView = ContentView().environmentObject(sceneState)
...
}
struct ContentView: View {
var body: some View {
NavigationView {
View1()
}
}
}
struct View1: View {
@EnvironmentObject var sceneState: SceneState
@State private var showView2: Bool = false
var body: some View {
VStack {
Text("NO nav bar.")
Button("Go to View2") {
self.showView2 = true
}
NavigationLink(destination: View2(), isActive: $showView2, label: {EmptyView()})
}
.navigationBarHidden(self.sceneState.isNavigationBarHidden)
.navigationBarTitle("")
.navigationBarBackButtonHidden(self.sceneState.isNavigationBarHidden)
}
}
struct View2: View {
@EnvironmentObject var sceneState: SceneState
var body: some View {
VStack {
Text("WITH nav bar.")
}
.navigationBarHidden(self.sceneState.isNavigationBarHidden)
.navigationBarTitle("WWDC")
.navigationBarBackButtonHidden(self.sceneState.isNavigationBarHidden)
.onAppear {
self.sceneState.isNavigationBarHidden = false
}
}
}
Upvotes: 1
Reputation: 3809
Edit: use the accepted answer as it's a much cleaner solution.
I encountered this bug and ended up using UIViewControllerRepresentable
to wrap a controller which sets the navigation bar hidden state in its viewDidAppear
method:
struct ContentView: View {
var body: some View {
NavigationView {
ZStack {
Color.red.frame(maxWidth: .infinity, maxHeight: .infinity)
NavigationLink(destination: DestinationView()) {
ZStack {
Color.green.frame(width: 200, height: 200)
Text("Tap me")
}
}
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
struct DestinationView: View {
var body: some View {
List {
Text("1")
Text("2")
}
.navigationBarTitle("DestinationView")
.navigationBarHidden(false)
.background(HorribleHack())
}
}
struct HorribleHack: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> HorribleHackViewController {
HorribleHackViewController()
}
func updateUIViewController(_ uiViewController: HorribleHackViewController, context: Context) {
}
}
class HorribleHackViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.async {
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
}
}
Upvotes: 1
Reputation: 64
There is an issue with the safe area layout guide
struct ContentView: View {
var body: some View {
NavigationView {
ZStack {
Color.red.frame(maxWidth: .infinity, maxHeight: .infinity)
VStack {
NavigationLink(destination: DestinationView()) {
ZStack {
Color.green.frame(width: 200, height: 200)
Text("Tap me")
}
}
}
}.edgesIgnoringSafeArea(.all)
.navigationBarHidden(true)
}
}
}
struct DestinationView: View {
var body: some View {
VStack {
List {
Text("1")
Text("2")
}
}.navigationBarTitle("DestinationView")
.navigationBarHidden(false)
}
}
Happy Coding...
Upvotes: 1
Reputation: 14397
You need to use variable to achieve this and bind it with your destination
struct ContentView: View {
@State var isNavigationBarHidden: Bool = true
var body: some View {
NavigationView {
ZStack {
Color.red.frame(maxWidth: .infinity, maxHeight: .infinity)
NavigationLink(destination: DestinationView(isNavigationBarHidden: self.$isNavigationBarHidden)) {
ZStack {
Color.green.frame(width: 200, height: 200)
Text("Tap me")
}
}
}
.navigationBarHidden(self.isNavigationBarHidden)
.navigationBarTitle("")
.onAppear {
self.isNavigationBarHidden = true
}
}
}
}
struct DestinationView: View {
@Binding var isNavigationBarHidden: Bool
var body: some View {
List {
Text("1")
Text("2")
}
.navigationBarTitle("DestinationView")
.onAppear {
self.isNavigationBarHidden = false
}
}
}
Upvotes: 21