Having the following situation here. Basically I want to have dynamic amount of tab bar items depending on a situation. In the provided example below when the button is tapped it will add one more tab in the middle of the array (index 1) where previously stayed case .five
. The problem I am having is that when the new .three
tab shows and I click on it the app crashes with the following error:
"Layout requested for visible navigation bar, <SwiftUI.UIKitNavigationBar: 0x100710c50; baseClass = UINavigationBar; frame = (0 24; 1024 102); opaque = NO; autoresize = W; gestureRecognizers = <NSArray: 0x600000c63390>; layer = <CALayer: 0x60000026e5a0>> delegate=0x110016200, when the top item belongs to a different navigation bar. topItem = <UINavigationItem: 0x100712790> title='Hello' style=navigator leftItemsSupplementBackButton largeTitleDisplayMode=always, navigation bar = <SwiftUI.UIKitNavigationBar: 0x10951dc00; baseClass = UINavigationBar; frame = (0 24; 1024 102); opaque = NO; autoresize = W; gestureRecognizers = <NSArray: 0x600000c8b960>; layer = <CALayer: 0x60000028ad60>> delegate=0x10f052800, possibly from a client attempt to nest wrapped navigation controllers."
The interesting part about it, is that it only happens on iOS 17+ and not on 16. The small POC I get the error on:
class ContentViewModel: ObservableObject {
@Published var tabs: [Tab] = [.one, .five]
static var shared = ContentViewModel()
}
struct ContentView: View {
@State var selection: Tab = .one
@StateObject var vm = ContentViewModel.shared
var body: some View {
TabView(selection: $selection) {
ForEach(vm.tabs, id: \.self) { tab in
tab
.tag(tab)
.tabItem {
Text(tab.rawValue)
}
}
}
}
}
enum Tab: String {
case one = "One"
case three = "Three"
case five = "Five"
}
extension Tab: View {
var body: some View {
NavigationStack {
switch self {
case .one:
Text("One")
case .three:
Text("Three")
case .five:
Button("Change") {
if ContentViewModel.shared.tabs.count == 3 {
ContentViewModel.shared.tabs.removeSubrange(1...1)
} else {
ContentViewModel.shared.tabs.insert(.three, at: 1)
}
}
.navigationTitle("Hello")
}
}
}
}
This was a bug several OSs ago, you should submit a report so it gets fixed again but as a workaround you can set an id for the TabView.
TabView(selection: $selection) {
ForEach(vm.tabs, id: \.rawValue) { tab in
tab
.tag(tab)
.tabItem {
Text(tab.rawValue)
}
}
}.id(vm.tabs.count) // <——Here
This redraws the entire TabView so it is very inefficient.