0

I have the following simplified code in a project using XCode 13.2. The intended functionality is to have 2 tabs (Tab1 and Tab2), and the user is able to tap the screen on Tab2 to toggle the background from red to green.

Instead, however, when Tab2 is clicked, the screen displays tab 1, instead of Tab2 with the changed color. I'm wondering why the app goes to Tab1 when Tab2 is tapped.

There are no NavigationLinks or actions that make the user go to Tab1. My only thought is that maybe the app is rebuilding when Tab2 is clicked, which is why it goes back to the first tab? If so, are there any good workarounds for this?

Note: the color still changes on Tab2, but not before the app switches to Tab1.


struct ContentView: View {
    
    var body: some View {
        TabView {
            Tab1()
                .tabItem {
                    Text("Tab 1")
                }
            Tab2()
                .tabItem {
                    Text("Tab 2")
                }
        }
    }
}

struct Tab1: View {
    var body: some View {
        Text("Tab 1")
    }
}

struct Tab2: View {
    @State var isRed: Bool = false
    
    var body: some View {
        if !isRed {
            Color.green
                .onTapGesture {
                    isRed = true
                }
        } else {
            Color.red
                .onTapGesture {
                    isRed = false
                }
        }
    }
}
Stoic
  • 945
  • 12
  • 22

2 Answers2

2

I have noticed that using if/else in that way causes strange behavior. Refactor Tab2 as shown below and it should work as expected.

struct Tab2: View {
@State var isRed: Bool = false

var body: some View {
    ZStack {
        Color.red
        Color.green
            .opacity(isRed ? 0 : 1)
    }
    .onTapGesture {
        isRed.toggle()
    }
}

}

David B.
  • 413
  • 4
  • 6
  • This worked, thanks! If you find out why this happens, let us know! – Stoic Dec 28 '21 at 00:45
  • @purpleprince if this answer worked, you should mark it as accepted. – Anwuna Dec 28 '21 at 02:17
  • @Anwuna I was going to keep it un-accepted, just because I was wondering whats actually happening and why the issue was occurring. The workaround was helpful though, so should I still mark it as accepted? – Stoic Dec 28 '21 at 02:30
  • 1
    If you haven't found an acceptable answer, then I think upvoting David's answer is good enough. – Anwuna Dec 28 '21 at 02:35
2

The reason why tapping on Tab2 causes it to jump back to Tab1 is that the structural identity of Tab2 changes whenever you tap on it causing swiftUI to reload the body. See the explanation here. A simple fix to the example you have above would be to wrap the entire body in a ZStack

var body: some View {
  ZStack {
    if !isRed {
      Color.green
        .onTapGesture {
          isRed = true
        }
    } else {
      Color.red
        .onTapGesture {
          isRed = false
        }
    }
  }
}
Anwuna
  • 1,077
  • 11
  • 18