Albi
Albi

Reputation: 1855

ForEach not working as expected in SwiftUI

In the current code when a text item is clicked the pageIndex gets updated but the UI doesn't react to the change

ForEach(T2Array) { ele in
            Text(ele.name)
                .foregroundColor(ele.isSelected ? Color.blue : Color.black)
                .onTapGesture {
                    print(pageIndex)
                    pageIndex = 4
                    print(pageIndex)
                }
        }

The same code but when the ForEach syntax is used in a different way it works, why is its happening

ForEach(0...T2Array.count-1,id:\.self) { i in
                        Text(T2Array[i].name)
                            .foregroundColor(T2Array[i].isSelected ? Color.blue : Color.black)
                            .onTapGesture {
                                print(pageIndex)
                                pageIndex = 4
                                print(pageIndex)
                            }
                    }

Full code

import SwiftUI

struct T1Object:Identifiable{
    let id = UUID()
    var isSelected = false
    let name:String
}

struct T1:View{

    @State var T1Array:[T1Object] = [
        T1Object(isSelected: true, name: "Albin"),
        T1Object(isSelected: false, name: "Albin2"),
        T1Object(isSelected: false, name: "Albin3"),
        T1Object(isSelected: false, name: "Albin4"),
        T1Object(isSelected: false, name: "Albin5"),
        T1Object(isSelected: false, name: "Albin6"),
    ]

@State var pageIndex:Int = 0

  var body: some View {
    VStack{
        T2(T2Array: $T1Array,pageIndex:$pageIndex)
        Text("selected Index:\(pageIndex)")
        }
    }
}

struct T2:View{

    @Binding var T2Array:[T1Object]
    @Binding  var pageIndex:Int

var body: some View {
    
    TabView(selection: $pageIndex) {
        //This doesnt work
        ForEach(T2Array) { ele in
            Text(ele.name)
                .foregroundColor(ele.isSelected ? Color.blue : Color.black)
                .onTapGesture {
                    print(pageIndex)
                    pageIndex = 4
                    print(pageIndex)
                }
        }
        
        
        //..................
        //This commented code works fine why?
        //..................
        //            ForEach(0...T2Array.count-1,id:\.self) { i in
        //                Text(T2Array[i].name)
        //                    .foregroundColor(T2Array[i].isSelected ? Color.blue : Color.black)
        //                    .onTapGesture {
        //                        print(pageIndex)
        //                        pageIndex = 4
        //                        print(pageIndex)
        //                    }
        //            }
        
    }.tabViewStyle(PageTabViewStyle(indexDisplayMode:.never))
    .animation(Animation.easeInOut(duration: 0.5))
    .transition(.slide)
 }

}


struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        T1()
    }
}

Can anyone explain the difference between the two?

Thnaks

Upvotes: 0

Views: 294

Answers (1)

Yrb
Yrb

Reputation: 9665

I think Paul Hudson explains it in this article: Creating tabs with TabView and tabItem() the gist of it is that the tabs are not an array of individual tabs, so to keep track of them you should use a tag(). Why using the index range works, I am not sure. I suspect it is because you end up with an index that mimics your page index, but that is not the same thing.

If you do use a page, your first one works properly. Of course, you need to use something unique to the array element, so I used it's UUID.

struct T1:View{
    
    @State var T1Array:[T1Object] = [
        T1Object(isSelected: true, name: "Albin"),
        T1Object(isSelected: false, name: "Albin2"),
        T1Object(isSelected: false, name: "Albin3"),
        T1Object(isSelected: false, name: "Albin4"),
        T1Object(isSelected: false, name: "Albin5"),
        T1Object(isSelected: false, name: "Albin6"),
    ]
    
    @State var pageIndex:UUID = UUID()
    
    init() { // the init() solely is here to set the pageIndex to the first element.
        pageIndex = T1Array.first!.id
    }
    
    var body: some View {
        VStack{
            T2(T2Array: $T1Array, pageIndex:$pageIndex)
            Text("selected Index:\(pageIndex)")
        }
    }
}


struct T2:View{
    
    @Binding var T2Array:[T1Object]
    @Binding  var pageIndex: UUID // make pageIndex a UUID (also in T1)
    
    var body: some View {
        
        TabView(selection: $pageIndex) {
            //This doesnt work
            ForEach(T2Array) { ele in
                Text(ele.name)
                    .tag(ele.id) // Set the .tag() here
                    .foregroundColor(ele.isSelected ? Color.blue : Color.black)
                    .onTapGesture {
                        print(pageIndex)
                        pageIndex = T2Array[3].id // This is the 4th element in T2Array
                        print(pageIndex)
                    }
            }
        }.tabViewStyle(PageTabViewStyle(indexDisplayMode:.never))
        .animation(Animation.easeInOut(duration: 0.5))
        .transition(.slide)
    }
}

Upvotes: 1

Related Questions