TechnologiesSwiftUI

SpatialTapGesture struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A gesture that recognizes one or more taps and reports their location.

How it works

SpatialTapGesture recognizes one or more taps and, unlike the simpler tap modifiers, reports exactly where the tap landed. Each recognized tap produces a SpatialTapGesture.Value carrying the contact location in the coordinate space you specify, so you can react to the position of a touch rather than just its occurrence. Reach for it when your view needs to know the point that was tapped — placing a marker, sampling a coordinate, or hit-testing against custom geometry — instead of merely toggling state on any tap.

  1. Create the recognizer with SpatialTapGesture()

    The initializer constructs a gesture that fires after a given number of taps. The default recognizes a single tap; pass a count to require a double- or triple-tap before the gesture succeeds. The example uses the bare SpatialTapGesture() form to react to each single tap of the box.

  2. Read the contact point from value.location

    When the gesture succeeds it delivers a SpatialTapGesture.Value whose location is the tap's position as a CGPoint. This is the distinguishing feature of the gesture — it tells you where, not just whether, the tap happened. The example reads value.location and stores it in the location state so a white Circle can be drawn at that exact spot.

  3. Respond with onEnded

    Because a tap is discrete, you handle it through onEnded, which runs once the required taps are recognized and hands you the final value. In the example the onEnded closure assigns value.location and sets tapped = true, which flips the rectangle's fill and updates the caption text.

  4. Attach it with the gesture(_:) modifier

    A gesture only takes effect once it's bound to a view via the .gesture(_:) modifier, which installs it on that view's interactive region. Here the SpatialTapGesture is attached to the RoundedRectangle, so taps anywhere within its frame are reported relative to that view.

  5. Pin the location to a coordinate space

    The reported location is expressed in a coordinate space; SpatialTapGesture defaults to the local space of the view it's attached to, and you can request another by passing coordinateSpace: to the initializer. The example relies on the local default, which is why value.location lines up directly with the Circle's .position(location) inside the same rectangle.

Try it — Change SpatialTapGesture() to SpatialTapGesture(count: 2) so the marker only moves on a double-tap, demonstrating how count gates when the gesture's onEnded fires.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

SpatialTapGesture.swift
struct SpatialTapGestureDemo: View {
    @State private var location: CGPoint = .zero
    @State private var tapped = false

    var body: some View {
        VStack(spacing: 16) {
            RoundedRectangle(cornerRadius: 12)
                .fill(tapped ? Color.green : Color.blue)
                .frame(width: 220, height: 140)
                .overlay(
                    Circle()
                        .fill(.white)
                        .frame(width: 16, height: 16)
                        .position(location)
                )
                .gesture(
                    SpatialTapGesture()
                        .onEnded { value in
                            location = value.location
                            tapped = true
                        }
                )
            Text(tapped ? "Tapped at (\(Int(location.x)), \(Int(location.y)))" : "Tap the box")
                .font(.callout)
        }
        .padding()
    }
}
Live preview
Tap the box
Tap the box
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →