When setting up a SwiftUI TabView with two tabs, the onChange closures of inactive (non visible) tabs that listen to a @State or @Binding variable will always get triggered when the variable is changed from the active tab.
I'd expect as long as the tab is not active the onChange should not get triggered. Basically the same it works when using two different navigation links. But I assume somehow it keeps the inactive tab fully alive in the background.
I've tried assigning tags to each tab view so that the view can identify the active tab. I read that this could solve the issue, however it does not.
Here is a simple SwiftUI app that shows the issues. When the second tab is active and I click the button, the onChange of the first tab will get triggered and print to the console.
Let me know if I need to provide a different example or if there are questions.
Note: This happens also when using onReceive and for example listening to the changes of an @Published variable of an ObservableObject.
import SwiftUI
struct ContentView: View {
@State var tabViewSelection: String = "Ant"
@State var value: Bool = false
var body: some View {
TabView(selection: $tabViewSelection) {
AntView(value: $value)
.tag("Ant")
.tabItem {
Image(systemName: "ant")
}
LadybugView(value: $value)
.tag("Ladybug")
.tabItem {
Image(systemName: "ladybug")
}
}
}
}
struct AntView: View {
@Binding var value: Bool
var body: some View {
Text("AntView")
.onChange(of: value) { value in
print("onChange new value = \(value)") // <-- will get triggered...
}
}
}
struct LadybugView: View {
@Binding var value: Bool
var body: some View {
VStack {
Text("LadybugView")
Button(action: {
value.toggle() // <-- ...when changing value here.
}, label: {
Text("Toggle value")
})
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}