Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Altering property in a SwiftUI ForEach loop

I have been trying to change the offset value of an object in SwiftUI, but can’t quite get it to work. I feel like there’s something basic I’m missing here.

Below is the main SwiftUI code. I am trying to change the offset value of each card in a stack as the user swipes. However, on line with "user.offset = value.translation.width", I get the error "Cannot assign to property: ‘user’ is a ‘let’ constant". I think I understand that that is because you are not actually able to change the object you are iterating through with a ForEach loop. However, I’m struggling to find a workaround.

import SwiftUI
import Kingfisher

struct GroupSessionView: View {
    @ObservedObject var userViewModel = ExploreUsersViewModel()
    
    func calculateWidth() -> CGFloat {
        let screen = UIScreen.main.bounds.width - 50
        let width = screen - (2*60)
        return width
    }
   
    var body: some View {
        VStack(spacing: 10) {
            ZStack {
                ForEach(Array(zip(userViewModel.userCards.indices, userViewModel.userCards)), id: \.0) { index, user in
                    HStack {
                        KFImage(URL(string: user.image))
                            .resizable()
                            .aspectRatio(contentMode: .fill)
                            .frame(width: calculateWidth(), height: (UIScreen.main.bounds.height / 3.5) - CGFloat(index*30))
                            .cornerRadius(15)
                            .offset(x: index <= 2 ? CGFloat(index * 30): 60)
                    }
                    .zIndex(Double(userViewModel.users.count - index))
                    .contentShape(Rectangle())
                    .offset(x: 0)
                    .gesture(DragGesture().onChanged({ value in
                        withAnimation {
                            user.offset = value.translation.width
                        }
                    }).onEnded({ (value) in
                        withAnimation {
                            user.offset = 0
                        }

                    }))
                           
                }
            }
            .frame(height: UIScreen.main.bounds.height / 3.5)
            .padding(.horizontal)
            .padding(.top)
            Spacer()
        }
        .padding(.top)
    }
}

And here is the view model I am working with to produce the userCards data.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class ExploreUsersViewModel: ObservableObject {
    @Published var users = [User]()
    @Published var userCards = [UserCard]()
    let service = UserService()
    
    init() {
        fetchUsers()
        getCards()
    }
    
    func fetchUsers() {
        service.fetchUsers { users in
            self.users = users
            
            print("Users are \(users)")
        }
    }
    
    func getCards() {
        service.fetchUsers { users in
            for user in users {
                self.userCards.append(UserCard(id: NSUUID().uuidString, image: user.profileImageUrl, fullName: user.fullname, offset: 0))
            }
        }
    }
}

>Solution :

In ForEach (as well as forEach) all index variables are constants.

But as you have the index the solution is pretty easy: Modify the item in the array directly

users[index].offset = value.translation.width
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading