Search code examples
arraysswiftswiftuiswiftui-foreachdraggesture

Modify view inside a ForEach in SwiftUI


I tried to update the position of one item of a ForEach. I want to drag only one item out of the array in the ForEach. The rest should stay the same. I tried several different ways and the outcome was always that all items where dragged or no item at all.

I am really frustrated at this stage, so I would be more than happy, if you can help me! If you need further information feel free to ask, I am new here on stackOverflow.

struct ContentView: View {

    var texts: [String] = ["Test1", "Test2"]

    @State var positon: CGSize = .zero

    var body: some View {
        HStack {
            ForEach(texts, id: \.self) { text in
                Text(text)
                    .offset(y: positon.height)
                    .gesture(
                        DragGesture()
                            .onChanged { value in
                                positon = value.translation
                            }
                            .onEnded { value in
                                positon = .zero
                            }
                    )
            }
        }
    }
}

Solution

  • Both Text views are dragged at the same time, because both Text views offset(y: ...) depend on the same position variable.


    Something like this should work:

    struct ContentView: View {
    
        var texts: [String] = ["Test1", "Test2"]
    
        var body: some View {
            HStack {
                ForEach(texts, id: \.self) { text in
                    DraggableText(text: text)
                }
            }
        }
    }
    
    struct DraggableText: View {
    
        var text: String
    
        @GestureState var position: CGSize = .zero
    
        var body: some View {
            Text(text)
                .offset(y: position.height)
                .gesture(
                    DragGesture().updating($position, body: { value, state, transaction in
                        state = value.translation
                    })
                )
        }
    }
    

    Each DraggableText has its own position property.