Richard Witherspoon
Richard Witherspoon

Reputation: 5019

SwiftUI Tab Selection Not Working With Any Hashable Content

SwiftUI’s Tab selection is suppose to work with any hashable content however that doesn’t seem to work.

In the example provided, you can see that in “Working” Tab, eveything works correctly if you use an integer for the tab selection. When you switch over to the “Broken” tab, the selection is a ColorItem and the selection does not update the view.

I believe this is a SwiftUI bug and have filed a feedback(FB8879981).

Tested with Xcode 12.2 and iOS 14.2(RC).

struct ColorItem: Identifiable, Hashable{
    let color: Color
    let title: String
    
    var id: String{
        title
    }
}
struct ContentView: View {
    let items = [
        ColorItem(color: .red, title: "Red"),
        ColorItem(color: .blue, title: "Blue"),
        ColorItem(color: .purple, title: "Purple")
    ]
    
    var body: some View {
        TabView{
            TabViewWorking(items: items)
                .tabItem {
                    Label("Working", systemImage: "hand.thumbsup")
                }
            
            TabViewBroken(items: items)
                .tabItem {
                    Label("Broken", systemImage: "hand.thumbsdown")
                }
        }
    }
}
struct TabViewWorking: View {
    @State private var tabSelection = 0
    let items: [ColorItem]
    
    var body: some View {
        ZStack{
            TabView(selection: $tabSelection){
                ForEach(0..<items.count){ i in
                    items[i].color.edgesIgnoringSafeArea(.all)
                        .tag(i)
                }
            }
            .tabViewStyle(PageTabViewStyle())
            
            VStack{
                Text(tabSelection.description)
                Text(items[tabSelection].title)
            }
            .font(.largeTitle)
        }
    }
}
struct TabViewBroken: View {
    @State private var tabSelection = ColorItem(color: .red, title: "Red")
    let items: [ColorItem]

    var body: some View {
        ZStack{
            TabView(selection: $tabSelection){
                ForEach(0..<items.count){ i in
                    items[i].color.edgesIgnoringSafeArea(.all)
                        .tag(i)
                }
            }
            .tabViewStyle(PageTabViewStyle())
            
            VStack{
                Text(items.firstIndex(of: tabSelection)?.description ?? "N/A")
                Text(tabSelection.title)
            }
            .font(.largeTitle)
        }
    }
}

Upvotes: 7

Views: 5319

Answers (1)

Asperi
Asperi

Reputation: 257543

No, it is not SwiftUI bug. Type of selection and type of tag must be same, so in your first scenario they are both integers, but in second one they are not same - selection is ColorItem, but tag is still integer - thus selection does not work.

Here is fixed variant:

struct TabViewBroken: View {
    @State private var tabSelection = ColorItem(color: .red, title: "Red")
    let items: [ColorItem]

    var body: some View {
        ZStack{
            TabView(selection: $tabSelection){
                ForEach(0..<items.count){ i in
                    items[i].color.edgesIgnoringSafeArea(.all)
                        .tag(items[i])                          // << here !!     
                }
            }
            .tabViewStyle(PageTabViewStyle())
            
            VStack{
                Text(items.firstIndex(of: tabSelection)?.description ?? "N/A")
                Text(tabSelection.title)
            }
            .font(.largeTitle)
        }
    }
}

Upvotes: 14

Related Questions