My drag tracker in a rectangle is erratic about whether it's listening

56 Views Asked by At

I have a 10x10 grid surrounded by a rectangle where I want to be able to select a group of cells. My intent is to track the pointer in the rectangle and calculate the coordinate for each cell it passes over as I drag through the array. I'm using Swift 5.9 in Xcode 15.1 on a MacBook Pro and the iPhone 15 Pro simulator. Right now, I'm just trying to print the mouse coordinates as the pointer passes through the rectangle and the calculated cell coordinates. On my Mac, when I click and start to drag, it is erratic about responding to the dragGesture. Once it starts tracking, it tracks reliably until I let up from the trackpad. But then it's erratic about starting again. The probability is higher that it will track if I start near the border of the rectangle.
Here I have to a simple view showing a 300x300 rectangle that I want drag through and see the pointer coords as I drag. When the dragGesture responds, I print the drag coordinates and the row and column of the cell that would have been selected. I want it would track every time I pressed on the trackpad inside the rectangle and stop when I lift up.

struct ContentView: View {
    var cellSize: Double = 30.0
    
    var body: some View {
        ZStack(){
            Rectangle()
                .stroke(.red, lineWidth: 6)
                .fill(.clear)
                .frame(width: 10 * cellSize, height: 10 * cellSize)
                .gesture(DragGesture(minimumDistance: 2,
                                     coordinateSpace: .local)
                    .onChanged() { drag in
                        print("Drag: raw: \(drag.location); Cell: \(Int(drag.location.y/cellSize)), \(Int(drag.location.x/cellSize))")
                    }
                    .onEnded() { drag in
                        print("DragEnd: \(drag.location)")
                    }
                )
        }
    }
}
1

There are 1 best solutions below

2
workingdog support Ukraine On BEST ANSWER

Try this approach using minimumDistance: 0 and .fill(.white.opacity(0.001)) instead of .fill(.clear). As you drag the mouse or finger inside the red bordered rectangle, the Cell info is displayed and printed.

Note, using .fill(.clear) does not capture the drag events for the Rectangle, but it does, if you use a color, such as .fill(.white.opacity(0.0001)), the equivalent of clear.

struct ContentView: View {
    let cellSize: Double = 30.0
    @State var info = "no info" // <-- for testing

    var body: some View {
        VStack {
            Text(info)  // <-- for testing
            Rectangle()
                .stroke(.red, lineWidth: 6)
                .fill(.white.opacity(0.0001))  // <-- here
                .frame(width: 10 * cellSize, height: 10 * cellSize)
                .gesture(DragGesture(minimumDistance: 0) // <-- here
                    .onChanged() { drag in
                        info = "Cell: \(Int(drag.location.y/cellSize)), \(Int(drag.location.x/cellSize))"
                        print("Drag: raw: \(drag.location); Cell: \(Int(drag.location.y/cellSize)), \(Int(drag.location.x/cellSize))")
                    }
                    .onEnded() { drag in
                        print("DragEnd: \(drag.location)")
                    }
                )
        }
    }
}