How do I correctly collect the click, drag and release of a mouse event for CanvasView in SwiftUI on MacOS
For this drawing application on MacOS using SwiftUI and I'm having an interesting issue. The DragGesture does not trigger when I click inside my Canvas. It does trigger if I click on an item in my toolbar, or right panel. I have disabled every single view (Toolbars, Right Panel, Rulers, RulerGrid etc) and the problem still persists.
Simplified CanvasView looks like this:
GeometryReader { geometry in
Path { path in
for curObj in dm.objects {
DrawingHelper.draw( curObj, in: geometry.size)
}
}
.stroke(lineWidth: 2)
.foregroundColor(.black)
.allowsHitTesting(true)
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { value in
currentPoints.append(value.location)
print( "in onChanged")
}
.onEnded { _ in
print( "in onEnded")
if currentPoints.count > 1 {
let newObject = DrawingObject(
tool: dm.curTool,
points: currentPoints,
...
)
dm.drawingObjects.append(newObject)
}
currentPoints.removeAll()
}
)
Edit-1 - How the CanvasView is being called
GeometryReader { geometry in
HStack (spacing: 0) { // Remove space on right
Rulers( dm ) {
ZStack { // Draw rulerGrid on top
CanvasView( dm ).background( .white )
if( dm.showRulerGrid == true ) {
RulerGrid( dm ).background( .clear )
}
}
} onRulerDoubleClick: { isShowingRulerSettings.toggle( )}
.popover(isPresented: $isShowingRulerSettings, arrowEdge: .trailing) {
RulerSettingsView( dm )
}
.background( .clear )
if( dm.showPanel ) {
RightPanelView( dm )
.background( .black )
.animation(.easeInOut( duration: 0.5) ) // TODO: Update this
.transition(.move(edge: .trailing))
} // End of Side Panel
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background( .clear )
}
Answers
It seems like the issue might be related to the layers of views in your SwiftUI hierarchy. Since the DragGesture
is not triggering when clicking inside the CanvasView
, it's possible that another view is intercepting the touch events before they reach the CanvasView
.
Here are a few things you can try to troubleshoot and potentially fix the issue:
-
Change Z-Index: Ensure that the
CanvasView
is placed at the top of the Z-index in your view hierarchy. You can achieve this by reordering the views inside theHStack
. Move theCanvasView
to the last position within theZStack
. -
Check for Overlapping Views: Make sure that there are no invisible or overlapping views above the
CanvasView
that might be intercepting the touch events. -
Hit Testing: Set
allowsHitTesting(true)
for all the parent views ofCanvasView
, including theHStack
and the outermostGeometryReader
. -
View Debugging: Use Xcode's View Debugger to inspect the view hierarchy during runtime. This can help you visualize the layout and identify any issues with view positioning or overlapping.
-
Explicit Frame: Provide an explicit frame to the
CanvasView
to ensure that it occupies the entire available space within its parent container. Sometimes, views may not receive touch events if their frame is not correctly defined. -
Remove Gesture Conflicts: Ensure that there are no conflicting gestures or event handlers defined in other parts of your code that might interfere with the
DragGesture
.
By applying these troubleshooting steps, you should be able to identify and resolve the issue with the DragGesture
not triggering within the CanvasView
.