I’ve a TabView with two tabs (FirstTab and SecondTab).
From the primary tab, I need to programmatically swap to the second tab after which instantly push a element display contained in the second tab’s NavigationStack
.
I wrote a simplified instance:
struct FirstTab: View {
var onNavigate: (String) -> Void
var physique: some View {
VStack {
Textual content("FirstTab")
Button("Go to SecondTab") {
onNavigate("Whats up from FirstView")
}
}
}
}
class SecondTabViewModel: ObservableObject {
@Printed var textToShow: String? = nil
}
struct SecondTab: View {
@ObservedObject var viewModel: SecondTabViewModel
@State non-public var path = NavigationPath()
var physique: some View {
NavigationStack(path: $path) {
VStack {
Textual content("SecondTab")
}
.navigationDestination(for: String.self) { worth in
DetailView(textual content: worth)
}
.onChange(of: viewModel.textToShow) { oldValue, newValue in
print("onChange SecondTab textual content: (String(describing: newValue))")
if let newValue = newValue, newValue != oldValue {
print("Pushing DetailView with: (newValue)")
path.append(newValue)
}
}
}
}
}
struct DetailView: View {
let textual content: String
var physique: some View {
VStack {
Textual content("DetailView")
Textual content("Textual content: (textual content)")
}
}
}
struct ContentView: View {
@State non-public var selectedTab = 0
@StateObject non-public var secondVM = SecondTabViewModel()
var physique: some View {
TabView(choice: $selectedTab) {
FirstTab { textual content in
print("Closure referred to as with textual content: (textual content)")
selectedTab = 1 // swap tab
DispatchQueue.foremost.asyncAfter(deadline: .now() + 1) {
secondVM.textToShow = textual content
}
}
.tabItem { Label("First", systemImage: "1.circle") }
.tag(0)
SecondTab(viewModel: secondVM)
.tabItem { Label("Second", systemImage: "2.circle") }
.tag(1)
}
}
}
The problem :
- The closure is appropriately referred to as once I faucet the button in FirstTab.
- The tab switches to SecondTab.
- I anticipate the DetailView to mechanically push within the
NavigationStack
.
However nothing seems – onChange is named, however no push happens.
If I wrap the textToShow
inside a DispatchQueue.foremost.asyncAfter
(e.g. 0.1 seconds), it really works.
Instance of the workaround:
FirstTab { textual content in
print("Closure referred to as with textual content: (textual content)")
selectedTab = 1 // swap tab
DispatchQueue.foremost.asyncAfter(deadline: .now() + 1) {
secondVM.textToShow = textual content
}
}
However this looks like a hack.
Why doesn’t the navigation push (path.append
) work when switching tabs instantly?
Is there a beneficial, clear manner in SwiftUI to vary tab after which push a vacation spot in that tab’s NavigationStack
?
Ought to I be utilizing a distinct navigation method (e.g. Coordinator, Observable shared state)?