TechnologiesSwiftUI

SpatialEventGesture struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A gesture that provides information about ongoing spatial events like

How it works

SpatialEventGesture is a gesture that reports a collection of spatial input events, letting a view respond to one or more simultaneous touches, pointer movements, or pinch interactions delivered with 3D location and phase information. Unlike single-point gestures such as TapGesture or DragGesture, it surfaces the full set of active events at once, which is what you need when input can arrive from several sources or fingers in parallel. Reach for it when you want low-level, per-event control over spatial input rather than a higher-level recognized gesture, attaching it to a view through the standard gesture(_:) modifier.

  1. Construct the gesture with SpatialEventGesture()

    Create the recognizer with its initializer and it begins tracking the spatial events that occur over the view it's attached to. In the example, SpatialEventGesture() is built inline and handed to .gesture(...) so events flowing across the card are routed to it.

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

    Like every SwiftUI gesture, SpatialEventGesture only becomes active once it's bound to a view via gesture(_:). Here the .gesture(...) modifier installs it on the VStack (wrapped by .background and .padding), defining the region where spatial events are collected.

  3. Read the event set in onChanged

    The onChanged modifier fires whenever the active events update, handing your closure the current events collection rather than a single point. The example reads events.count to learn how many spatial events are in flight at that moment and stores it in count.

  4. Drive view state from the events

    Because the closure runs on each change, it's the place to translate raw spatial input into observable state. Assigning count = events.count updates the @State private var count, so the Text("Spatial events: \(count)") label re-renders to reflect how many events are currently being tracked.

Try it — In the onChanged closure, change count = events.count to count = max(count, events.count) so the label holds the peak number of simultaneous spatial events instead of resetting back toward zero as inputs lift.

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.

SpatialEventGesture.swift
struct SpatialEventGestureDemo: View {
    @State private var count = 0

    var body: some View {
        VStack(spacing: 16) {
            Image(systemName: "hand.point.up.left")
                .font(.system(size: 44))
                .foregroundStyle(.tint)
            Text("Spatial events: \(count)")
                .font(.headline)
        }
        .padding(40)
        .background(.regularMaterial, in: .rect(cornerRadius: 16))
        .gesture(
            SpatialEventGesture()
                .onChanged { events in
                    count = events.count
                }
        )
        .padding()
    }
}
Live preview
Spatial events: 0
Spatial events: 0
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →