Search code examples
swiftuiswiftui-navigationlinkswiftui-tabview

NavigationStack and TabView in Swiftui iOS 16: bug or improper usage?


[Xcode 14.1, iOS 16.1] I have a NavigationStack with a navigationTitle and a TabView with 2 Views. Each View has a ScrollView (see image below):

NavigationStack and TabView problem image

When I tap on Tab1 (#1 in red on the image above), then swipe up, the behavior is as expected (#2), i.e. the big navigationTitle move to the center, and my view passes below and becomes blurry. Perfect. However, when I tap ton Tab2 (#3) and then swipe up (#4), the big title stays big, and the view doesn't become blurry. Then I tap on Tab1 again (#5) and it works as expected.

Please help!

Here is my code:

ContentView:

import SwiftUI

struct ContentView: View {
   
   @State private var selection: Tab = .tab1
   enum Tab {
      case tab1
      case tab2
   }
   @State private var mainTitle = "Tab1"
   
    var body: some View {
        
       NavigationStack {
          
          TabView(selection: $selection) {
             
             Tab1(mainTitle: $mainTitle)
                 .tabItem {
                     Label("Tab1", systemImage: "wrench.adjustable.fill")
                 }
                 .tag(Tab.tab1)
             
             Tab2(mainTitle: $mainTitle)
                 .tabItem {
                     Label("Tab2", systemImage: "wrench.adjustable.fill")
                 }
                 .tag(Tab.tab2)
             
          } .navigationTitle(mainTitle)
          
       }
       
    }
}

Tab1:

import SwiftUI

struct Tab1: View {
   @Binding var mainTitle : String
   
    var body: some View {
       ScrollView {

          Text("Text tab 1")
             .padding(.all,100)
             .background(.blue)
       } .onAppear {
          mainTitle = "Tab1"
       }
    }
}

Tab2:

import SwiftUI

struct Tab2: View {
   @Binding var mainTitle : String
   
    var body: some View {
       ScrollView {

          Text("Text tab 2")
             .padding(.all,100)
             .background(.green)
       } .onAppear {
          mainTitle = "Tab2"
       }
    }
}

I tried a hack that is supposed to fix the transparency bug for Tab bars, but it doesn't work.

.onAppear {
let tabBarAppearance = UITabBarAppearance()
                tabBarAppearance.configureWithOpaqueBackground()
                UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance
}

Solution

  • TabViews are designed to sit at the top of the navigation hierarchy. They're intended to allow users to switch between independent sections of your app at any time.

    You would generally put a separate navigation stack within each tab that then handles pushing and popping of views. And then, you can use the navigationTitle modifier to manage the screen's title.

    So your structure (which might be split over multiple custom views) should look something like:

    TabView {
      NavigationStack {
        ScrollView {
        }
        .navigationTitle("Tab 1")
      }
      .tabItem { Label("Tab1", ...) }
      NavigationStack {
        ScrollView {
        }
        .navigationTitle("Tab 2")
      }
      .tabItem { Label("Tab2", ...) }
    }
    

    This structure is by design, to align with Apple's Human Interface Guidelines. It's worth reading the HIG to get a handle on where Apple are coming from, and how working on the same principles can really help your app feel like it belongs on your users' device.