iosswiftuiswiftui-gesture

Detecting SwiftUI drag Began event


I want to detect where the drag gesture first began. I have a subview that is only 20 points wide. I add a Drag Gesture to the super view and want to move around this subview only if the drag gesture start location at the beginning of the gesture was within 20 points of the location of this subview. I do not want to add drag gesture to this subview as it has caused other problems in the code (reported in other SO questions and with no clean solution). So I try adding the Gesture to the superview instead.

I have tried the following code but it doesn't work as it doesn't detect when & where the gesture BEGAN.

  DragGesture(minimumDistance: 0)
                    .updating($scrubberSeeking, body: { value, state, _ in
                        
                        if abs(value.startLocation.x - scrubberOffset) > 20.0  {
                            state = false
                            return
                        }
                        
                        state = true
                    })
                    .onChanged({ value in
                        
                            if scrubberSeeking {
                                ...
                                ...
                            }
                       

                    })
                    .onEnded { value in
                        
                    }

Solution

  • To detect where the drag gesture first started, try this approach storing the start of a drag into a var dragStartPosition in .onChanged.

    Then resetting that var to nil in .onEnded after completing any desired logic, as shown in the example code:

    struct ContentView: View {
        @State private var isDragging = false
        @State private var dragStartPosition: CGPoint?
        
        var body: some View {
            Circle()
                .fill(isDragging ? Color.red : Color.blue)
                .frame(width: 100, height: 100)
                .gesture(
                    DragGesture(minimumDistance: 0)
                        .onChanged { value in
                            if dragStartPosition == nil {
                                dragStartPosition = value.startLocation
                                print("---> dragStartPosition is: \(dragStartPosition)")
                                isDragging = true
                            }
                        }
                        .onEnded { value in
                            if let startPosition = dragStartPosition {
                                print("------> startPosition was: \(startPosition)")
                            }
                            dragStartPosition = nil
                            isDragging = false
                        }
                )
        }
    }
    

    EDIT-1

    code example to also drag the Circle as well as answering the question of how to detect where the drag gesture first started.

    struct ContentView: View {
        @State private var isDragging = false
        @State private var dragStartPosition: CGPoint?
        @State private var circlePos: CGPoint = CGPoint(x: 100, y: 100)
        
        var body: some View {
            Circle()
                .fill(isDragging ? Color.red : Color.blue)
                .frame(width: 100, height: 100)
                .position(circlePos)
                .gesture(
                    DragGesture(minimumDistance: 0)
                        .onChanged { value in
                            if dragStartPosition == nil {
                                dragStartPosition = value.startLocation
                                print("---> dragStartPosition is: \(dragStartPosition)")
                                isDragging = true
                            }
                            circlePos = value.location
                        }
                        .onEnded { value in
                            if let startPosition = dragStartPosition {
                                print("------> startPosition was: \(startPosition)")
                            }
                            dragStartPosition = nil
                            isDragging = false
                        }
                )
        }
    }