Home > Software engineering >  SwiftUI View Switch Statement Causes TabView to Reset
SwiftUI View Switch Statement Causes TabView to Reset

Time:06-23

I am using a switch statement in a SwiftUI view:

struct OnOffSwitchView: View {
    
    @ObservedObject var vm = ViewModel()
    
    var body: some View {
        switch vm.state {
        case .on:
            OnView(vm: vm)
        case .off:
            OffView(vm: vm)
        }
    }
}

@MainActor class ViewModel: ObservableObject {
    @Published var state: State = .on

    enum State {
        case on
        case off
    }
}

Where the child views are changing the ViewModel state (on and off are the same) such that the switch condition updates, rendering a new view:

struct OnView: View {
    
    @ObservedObject var vm: ViewModel
    
    var body: some View {
        VStack {
            Text("Welcome to On")
            Button { vm.state = .off }
                label: { Text("Toggle") }
        }
    }
}

This works fine in a single view:

Toggle Single View

But, when nesting in a tab view, changing the state causes the TabView to change tabs:

Toggle Tab View

    TabView {
        Text("Home Tab")
            .tabItem {
                Image(systemName: "house.fill")
                Text("Home")
            }
        OnOffSwitchView()
            .tabItem {
                Image(systemName: "switch.2")
                Text("Switch")
            }
    }

Any ideas why this happening? I am unsure if (1) there is a problem with my setup (managing the state change), (2) I am missing something in the TabView, or (3) it's an issue with SwiftUI.

This toy example is available on GitHub Updated with answer.

CodePudding user response:

I think it is a bug, because OnOffSwitchView should be detected identical (by default properties-based convention)... anyway introducing explicit selection solves the issue

Tested with Xcode 13.4 / iOS 15.5

struct ContentView: View {

    @State private var selection = 0

    var body: some View {
        TabView(selection: $selection) {  // << preserves selected tab !!
            Text("Home Tab")
                .tabItem {
                    Image(systemName: "house.fill")
                    Text("Home")
                }.tag(0)
            OnOffSwitchView()
                .tabItem {
                    Image(systemName: "switch.2")
                    Text("Switch")
                }.tag(1)
        }
    }
}

*Note: I would recommend in this case use StateObject for view model in OnOffSwitchView.

  • Related