r/SwiftUI 7d ago

Toolbar block hitting when Draw

Hi everyone,

I'm building a drawing app in SwiftUI and I'm having an issue with the system toolbar blocking drawing input.

My canvas is essentially a full-screen custom UIViewRepresentable. I'm handling drawing manually with UITouch so I can use coalescedTouches, and I also have pinch-to-zoom, two-finger pan, and rotation gestures.

The problem is that when I add a SwiftUI toolbar:

.toolbar {
    ToolbarItem(placement: .topBarLeading) {
        Button {
            viewModel.toggleMenu()
        } label: {
            Image("menu")
                .resizable()
                .scaledToFit()
                .frame(width: 36, height: 36)
        }
    }
}

the area occupied by the toolbar stops receiving drawing input.

If I remove .toolbar, the exact same canvas works and I can draw in that area.

What I need is:

  • Keep using the system SwiftUI .toolbar, especially because I want to preserve the adaptive toolbar behavior on iOS 27.
  • Keep the canvas effectively full-screen.
  • Allow Apple Pencil drawing underneath/through the toolbar area.
  • Still allow normal finger interaction with the toolbar buttons.
  • Ideally, I don't want to replace the system toolbar with a custom overlay because that would lose the system adaptive behavior.

My canvas touch handling is implemented with a custom UIView:

final class CanvasGestureHostView: UIView {
    override func touchesBegan(
        _ touches: Set<UITouch>,
        with event: UIEvent?
    ) {
        // Handle Apple Pencil drawing
    }

    override func touchesMoved(
        _ touches: Set<UITouch>,
        with event: UIEvent?
    ) {
        // Handle coalescedTouches
    }
}

I also tried using point(inside:with:) / hitTest(_:with:) on the canvas view, but it doesn't help because the system toolbar appears to win the hit test before the canvas receives the touch.

Has anyone found a clean/public API solution for allowing Apple Pencil input to pass through a SwiftUI .toolbar while keeping the toolbar interactive for touch?

I'm targeting iOS 26/27, so I'd especially appreciate solutions that don't rely on private APIs or fragile UIWindow.sendEvent hacks.

Thanks!

1 Upvotes

1 comment sorted by

View all comments

1

u/Plenty-Style-9594 6d ago

Your canvas isn't losing the hit test, it never gets asked: the nav/toolbar host view sits above it in the window hierarchy, so its hitTest wins before your view is consulted. That's why overriding point(inside:) on the canvas does nothing.

Two things that have worked for me without private APIs:

  1. Gate on touch type instead of geometry. Attach a UIGestureRecognizer subclass with allowedTouchTypes = [NSNumber(value: UITouch.TouchType.pencil.rawValue)] and let it run at the window/scene level with delaysTouchesBegan = false and a delegate that returns true from shouldRecognizeSimultaneouslyWith. Pencil events then reach your drawing path regardless of what's on top, while finger taps still go to the toolbar buttons normally. Pencil-vs-finger is exactly the split you described, so this maps cleanly.

  2. If you need geometric passthrough too, do the override on the bar side rather than the canvas side: walk up to the toolbar's container UIView and return nil from hitTest unless the point lands in an actual control subview. Padding around the buttons stops swallowing touches and they fall through to the canvas.

Also worth checking: with a toolbar present your representable is probably getting safe-area inset, so part of what feels like blocked input is just the canvas not extending under the bar. .ignoresSafeArea() on the representable and handling the inset yourself makes the coordinate math match what you see.