0

The .navigationTitle on some views seem to be having some problems. On some views (and only some of the time), the .navigationTitle will not change from .large to .inline as would be expected. Instead, the title stays in place when scrolling up, and the navigation bar is completely invisible (as outlined in the video below). This is all reproducible every time.

Video of reproducible .navigationTitle bugs

I haven't found any people on stack overflow or the Apple Developer forums who have run into this exact issue. There have some people who have produced similar results as this, but those were all fixed by removing some stylizing code to the .navigationbar, of which I am not making any modifications to it anywhere in my code.

Below are some snippets of my code:

import SwiftUI
struct WelcomeUI: View { 
   var body: some View {
      NavigationView {
         VStack {
            //NavigationLink(destination: SignupUI(), label: {
               //Text("Sign Up")
            //}
            NavigationLink(destination: LoginUI(), label: {
               Text("Log In")
            })
         }
      }
   }
}


struct LoginUI: View {
   var body: some View {
      VStack {
         
         NavigationLink(destination: MainUI(), label: { Text("Log In") })
         //Button(action: { ... }
      }
   .navigationBarHidden(false)
   }
}


struct MainUI: View {
    @State var selectedTab: Views = .add
    var body: some View {
        
        TabView(selection: $selectedTab) {
            SpendingView()
                .tabItem {
                    Image(systemName: "bag.circle")
                    Text("Spending")
                }.tag(Views.spending)
            Text("Adding View")
                .tabItem {
                    Image(systemName: "plus")
                    Text("Add")
                }.tag(Views.add)
            Text("Edit View")
                .tabItem {
                    Image(systemName: "pencil")
                    Text("Edit")
                }.tag(Views.edit)
            SettingsView()
                .tabItem {
                    Image(systemName: "gear")
                    Text("Settings")
                }.tag(Views.settings)
        }
        .navigationBarTitle(Text(selectedTab.rawValue))
        .navigationBarBackButtonHidden(true)
    }
}


enum Views: String {
    case spending = "Spending"
    case add = "Add"
    case edit = "Edit"
    case settings = "Settings"
}


struct SettingsView: View {
    var body: some View {
        VStack{
            ZStack {
                Form {
                    Section(header: Text("Section Header")) {
                        NavigationLink(destination: WelcomeUI()) {
                            Text("Setting Option")
                        }
                    }
                    Section {
                        //Button("Log Out") {
                        //self.logout()
                        //}
                        Text("Log Out")
                    }
                }
                Button("say-high", action: {print("Hi")})
            }
        }
    }
}

struct SpendingView: View {
    var body: some View {
        ScrollView{
            Text("SpendingView")
            NavigationLink("subSpending", destination: SubSpendingView())
        }.padding()
    }
}
struct SubSpendingView: View {
    var body: some View {
        ScrollView{
            Text("SubSpendingView")
            
        }.navigationBarTitle("SubSpending")
    }
}

It almost seems like a bug in SwiftUI itself just because the fact that bringing down the control centre makes it kind of work, but with no animation (as seen in the video). Also, changing which view is selected first in @State var selectedTab: Views seems to let the view selected to work as expected, but lets the rest of the tabs mess up.

When I build and run the app on my iPad, it behaves as expected with no bugs, it's only when run on my iPhone and the iOS simulator on Mac that it does this, any way to fix this?

YourManDan
  • 277
  • 1
  • 14

2 Answers2

1

For this to work flawlessly the ScrollView needs to be the direct child of the NavigationView. I ran into a similar issue with wanting to dismiss the TabView when I navigating but SwiftUI won't let that happen. Each tab needs to be a NavigationView and you need to dismiss the TabView creatively if that is what you want.

TabView {
    NavigationView {
        ScrollView {
            // your view here
        }
    }.tabItem {
        // tab label
    }
    
    // etc
}

Essentially the navigation view needs to be a child (in the brackets) of the tab view and the scrollview needs to be the direct child of the navigation view.

BJ Beecher
  • 195
  • 1
  • 5
  • I've noticed also that the problem goes away if I'm running the app on my iPad, but appears again when I run it through my iPhone or the iOS simulator. For this reason, I can't imagine it having anything to do with your answer, but I'll give it a try nonetheless. I've updated the post accordingly with that information. – YourManDan Dec 16 '20 at 16:38
  • I'm going to need more clarification as to what you are talking about. Can you add some example code (possibly using the example code I posted) or explain better where the NavigationView wrappers need to go? – YourManDan Dec 16 '20 at 16:49
  • Still not following your train of thought here. Where do I place the NavigationView { ScrollView { } } tabs? Why do I need to dismiss the TabView? And wouldn't emitting the TabView view cause the tabs to not work? I'm not understanding what your solution is – YourManDan Dec 21 '20 at 03:08
  • Much better thank you. I tried doing exactly that in the `MainUI` View, but [this](https://imgur.com/a/QZtabWl) is what happens (none of the view elements display and the app get slow and choppy in places). I tried it with just `NavigationView`, emitting the `ScrollView` from your example and [this](https://imgur.com/a/6IxXcLU) is what happens (view elements display, but `navigationTitle` doesn't change states). You'll notice also that the same things happen if you apply your code to my example code in my question. – YourManDan Dec 21 '20 at 15:44
  • Make sure you aren't nesting NavigationViews.. Which means if WelcomeView is your entry point into the app and you navigate to your tabview (which contains NavigationViews) then NavigationView was already declared and redeclaration will cause bugs. – BJ Beecher Dec 21 '20 at 16:13
  • Take a look at my answer for this question on how to do navigation manually in SwiftUI. https://stackoverflow.com/questions/65333372/pure-swiftui-login-signup-register-flow-is-it-possible/65333667?noredirect=1#comment115565329_65333667 – BJ Beecher Dec 21 '20 at 16:14
  • Turns out this was the right answer! I just had to remove the `NavigationView` wrapper in the `WelcomeUI` view and handle the navigation creatively with some bindings. Thanks! +1 – YourManDan Dec 25 '20 at 02:15
  • No problem.. Glad I could help! – BJ Beecher Dec 25 '20 at 03:15
0

Use navigationBarTitle("Title") and navigationBarBackButtonHidden(true) on the TabView's sub-view, not on itself.

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                
            }
            .navigationBarTitle("Title")
            .navigationBarBackButtonHidden(true)
        }
    }
}
mahan
  • 12,366
  • 5
  • 48
  • 83
  • I've tried this quite a few times in multiple combinations and multiple locations. The solution I have in my example is the only way I've found to make the `.navigationTitle` show up at all. – YourManDan Dec 21 '20 at 02:48