2

been searching for this everywhere and can't find anything around this, I believe is a bug, maybe is not.

I need NavigationView with .navigationViewStyle(.stack) to have it stacked on the iPad and make it look the same as the iphone, now suppose you have this view:

import SwiftUI

struct ContentView: View {
    @State var isShowingProfile = false
    @State var isNavigationViewShowing = true
    
    var body: some View {
        if isNavigationViewShowing {
            NavigationView {
                VStack {
                    Button("Simple view") {
                        isNavigationViewShowing = false
                    }
                    .padding()
                    Button("Profile navigation") {
                        isShowingProfile = true
                        
                    }
                    .padding()
                    NavigationLink(
                        destination: ProfileView(),
                        isActive: $isShowingProfile
                    ) {
                        EmptyView()
                    }
                }
                .frame(
                    minWidth: 0,
                    maxWidth: .infinity,
                    minHeight: 0,
                    maxHeight: .infinity
                )
                .background(Color.gray)
                .navigationBarHidden(true)
            }
            .navigationViewStyle(.stack)
        } else {
            VStack {
                Button("Show NavigationView"){
                    isNavigationViewShowing = true
                    
                }
                .padding()
            }
            .frame(
                minWidth: 0,
                maxWidth: .infinity,
                minHeight: 0,
                maxHeight: .infinity
            ).background(Color.yellow)
        }
    }
}

struct ProfileView: View {
    var body: some View {
        Text("This is a profile")
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Well this just show this 3 simple views:

  • The navigationView when you start

The navigationView when you start

  • The Profile view if you tap on "Profile navigation"

Profile view

  • Finally the Simple view which is trigger by the conditional state pressing "Simple view"

Simple view

Up to here is all fine and good.

The problem is when navigate to the "Simple view" and then tap "Show NavigationView" to navigate back to the NavigtionView.

The app opens the first view (NavigationView), but the NavigationView ignores the .navigationBarHidden(true) and just show a big empty space on the top. In fact, it would ignore things like .navigationBarTitleDisplayMode(.inline) and just show the large version of the navigationBar

Broken navigationView

This is working correctly in all iOS 14.x, but on iOS 15.0 seems broken. The behaviour continues to be the same on iOS 15.1 beta.

Any idea whats going on? I'm not really interested in changing the conditionals on the view, because real life app is more complex.

Also, I tried ViewBuilder without any success. And if I take out .navigationViewStyle(.stack) it works all fine on iOS 15, but then the view on the iPad is with the side menu.

Thanks a lot for any tip or help, you should be able to reproduce in simulator and real device.

Video of the explained above

Javier Vieira
  • 2,100
  • 20
  • 23
  • I am trying to parse what you want. Are you saying that you don't ever want to see the navigation bar for any of the views? – Yrb Sep 26 '21 at 20:21
  • Exactly, the code is the always the same, is just that when you tap the button "Simple view", then when you go back to the view with the NavigationView it just ignore the `.navigationBarHidden(true)` and doesn't seems like the first image, seems like the last image. If in the last image, you tap profile navigation and use the navigation link and come back, then it fix it self. You can try all my code on a simulator and you will see the issue, which I can't reproduce in iOS 14 – Javier Vieira Sep 26 '21 at 20:25
  • @Yrb updated the question with a video of what happens https://streamable.com/rgqkef – Javier Vieira Sep 26 '21 at 20:37
  • That is what I was seeing. My question was more of what do you want, not what was it doing. See the answer below. – Yrb Sep 26 '21 at 20:38
  • This has to be a bug, I have exactly the same issue, was fine on iOS14.* and is broken on iOS15 – Brett Oct 14 '21 at 05:42

2 Answers2

1

I think the better solution all around is to not have the NavigationView be conditional. There is no reason your conditional can't just live in the NavigationView. You just don't ever want the bar to show. Therefore, this code would seem to meet the requirements:

struct ContentView: View {
    @State var isShowingProfile = false
    @State var isNavigationViewShowing = true
    
    var body: some View {
        NavigationView {
            Group {
                if isNavigationViewShowing {
                    VStack {
                        Button("Simple view") {
                            isNavigationViewShowing = false
                        }
                        .padding()
                        Button("Profile navigation") {
                            isShowingProfile = true
                            
                        }
                        .padding()
                        NavigationLink(
                            destination: ProfileView(),
                            isActive: $isShowingProfile
                        ) {
                            EmptyView()
                        }
                    }
                    .frame(
                        minWidth: 0,
                        maxWidth: .infinity,
                        minHeight: 0,
                        maxHeight: .infinity
                    )
                    .background(Color(UIColor.systemGray6))
                } else {
                    VStack {
                        Button("Show NavigationView"){
                            isNavigationViewShowing = true
                            
                        }
                        .padding()
                    }
                    .frame(
                        minWidth: 0,
                        maxWidth: .infinity,
                        minHeight: 0,
                        maxHeight: .infinity
                    ).background(Color.yellow)
                }
            }
            .navigationBarHidden(true)
        }
        .navigationViewStyle(.stack)
    }
}

I used Group simply to put the .navigationBarHidden(true) in the correct place so the code would compile.

Is this the behavior you are looking for?

Yrb
  • 8,103
  • 2
  • 14
  • 44
  • Well, I don't want the bar to show in this example.... the problem with this approach is that if you have really nested views in a big tree, then you have to live with a NavigationView as your root component. There could be cases when you want a NavigationView with different properties, like showing the title or inline, etc, and for that the conditiional before is a good reason for example. What I still don't get is why my code works just fine in all version < 15.0, I was wondering what has changed, if somethting has change or if it's a bug – Javier Vieira Sep 26 '21 at 20:44
  • I am not sure what may have changed, but I don't think it is a bug. If you want a `NavigationView` with different properties, you simply change the property on the view. It isn't recommended that you have multiple `NavigationViews` in an app. It has always been recommended that you have one `NavigationView` at your root, if you are going to need one anywhere. – Yrb Sep 26 '21 at 20:51
  • Well really appreciate your comments, I still think there is something fishy here, because this only happens when in use also with `.navigationViewStyle(.stack)` if the navigationViewStyle is not stack, then it never happens on a iPhone. Thanks a lot again. – Javier Vieira Sep 26 '21 at 20:57
  • i image that if you want to change if `.navigationBarHidden(true)` or other properties of the `NavigationView` how do you do? you past bindings around? thanks again mate – Javier Vieira Sep 26 '21 at 21:04
  • 1
    You set it in the view. So if a certain view you want to change whether you see the navigation bar, you simply use `.navigationBarHidden(false)` for that view. That is the way it is designed to work. – Yrb Sep 26 '21 at 21:08
  • I refactor the code of my app with your suggestions and is working good. Not sure yet why the convinantion of this factor of my code screw the view on iOS 15, but thanks a lot for your help and for me is answered with your suggestiongs – Javier Vieira Sep 28 '21 at 19:49
1
    import SwiftUI

struct ContentView: View {
    @State private var isShowingProfile = false
    @State private var showSimple = false
    
    var body: some View {
        
        NavigationView {
            VStack {
                Button("Simple view") {
                    showSimple = true
                }
                .padding()
                Button("Profile navigation") {
                    isShowingProfile = true
                    
                }
                .padding()
                NavigationLink(destination: ProfileView(), isActive: $isShowingProfile) {
                    EmptyView()
                }
            }
            .fullScreenCover(isPresented: $showSimple, onDismiss: {
                print("Dismissed")
            }, content: {
                SimpleView()
            })
            .frame(
                minWidth: 0,
                maxWidth: .infinity,
                minHeight: 0,
                maxHeight: .infinity
            )
            .background(Color.gray)
            .navigationBarHidden(true)
        }
        .navigationViewStyle(.stack)
        
    }
}

struct ProfileView: View {
    var body: some View {
        Text("This is a profile")
    }
}

struct SimpleView: View {
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        VStack {
            Button("Show NavigationView") {
                presentationMode.wrappedValue.dismiss()
            }
            .padding()
        }
        .frame(
            minWidth: 0,
            maxWidth: .infinity,
            minHeight: 0,
            maxHeight: .infinity
        ).background(Color.yellow)
    }
}
  • will this work? – cburnett837 Sep 27 '21 at 20:27
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 27 '21 at 22:55
  • @cburnett837 I didn't know about `fullScreenCover` looks interesting, the only problem that I see with this, is that in my example I hace a `if` and `else` which your code seems to work, but if you have many cases 5 for example ´if´ ´if else´ ´if else´ ´if else´ ´if else´ ´else´ not sure if your approach would work – Javier Vieira Sep 28 '21 at 19:48
  • I’m not sure what your end game is. But can add several full screen covers and have them attached to different buttons. Would that work? – cburnett837 Sep 29 '21 at 13:15
  • @cburnett837 yes, of course, now I get it, you are totally right. – Javier Vieira Sep 29 '21 at 14:03