Search code examples
swiftswiftuigesture

How can I select only one button from a `ForEach`?


I have some data and done a ForEach to write them in buttons. Then I have a onLongPressGesture and I want to change the background color of a specific button when long pressed. How can I achieve it?

Here is my code.

@State var selectedSummaryOption = "Daily"
    var hi = false
    var summaryOptions:[String] = ["Daily", "Weekly", "Monthly"]
    @State var prayerTimesImage = [
        prayerTimesImages(name: "Fajr", isActive: false),
        prayerTimesImages(name: "Zuhr", isActive: false),
        prayerTimesImages(name: "Asr", isActive: false),
        prayerTimesImages(name: "Maghrib", isActive: false),
        prayerTimesImages(name: "Isha", isActive: false)]
VStack {
                                    ForEach(prayerTimesImage, id: \.id) {prayerIcon in
                                        Button(action: {}) {
// HS -- Content of Button
                                            HStack {
                                                Image(prayerIcon.name)
                                                    .resizable()
                                                    .aspectRatio(contentMode: .fit)
                                                    .frame(width: 50, height: 50)
                                                Text("\(prayerIcon.name)")
                                                Spacer()
                                            }
                                            .padding(.horizontal, 5)
                                            .padding(.vertical, 10)
                                            .background(prayerIcon.isActive ? Color.green : Color.white)
                                            //.scaleEffect(longPressed ? 0.98 : 1)
                                            .onLongPressGesture(minimumDuration: 1) {
                                                prayerIcon.isActive = true   //gives error
                                                print(prayerIcon.isActive)
                                            }
                                            
                                        }.cornerRadius(10)
                                        .shadow(radius: 2)}
                                        .font(.system(.headline))
                                        .foregroundColor(.black)
                            }
                        }.frame(width: totalWidth, alignment: .center)

Solution

  • The prayerIcon is a copy, that's why you get an error. Use enumerated to have both index & item and change model directly in state property container, like

    ForEach(Array(prayerTimesImage.enumerated()), id: \.1.id) { (index, prayerIcon) in
    
         ...
    
        .onLongPressGesture(minimumDuration: 1) {
            prayerTimesImage[index].isActive = true   // << change in model
        }
    }