swiftui-gestures
Implement, review, or improve SwiftUI gesture handling. Use when adding tap, long press, drag, magnify, or rotate gestures, composing gestures with simultaneously/sequenced/exclusively, managing transient state with @GestureState, resolving parent/child gesture conflicts with highPriorityGesture or
By dpearson2699 · 3,464 installs
npx skills add dpearson2699/swift-ios-skills --skill swiftui-gestures
Source repository · Upstream listing
SwiftUI Gestures (iOS 26+)
Review, write, and fix SwiftUI gesture interactions. Apply modern gesture APIs
with correct composition, state management, and conflict resolution using
Swift 6.3 patterns.
Scope boundary: This skill owns SwiftUI gesture recognition, composition,
gesture state, and gesture specific accessibility alternatives. Broader
SwiftUI architecture/state ownership belongs in swiftui patterns ; list,
scroll, form, and control layout belongs in swiftui layout components ; broad
UIKit bridging belongs in swiftui uikit interop .
When correcting Apple API availability, deprecation, or behavior claims, cite
the relevant Sosumi or official Apple documentation URL in the response.
Contents
[Gesture Overview]( gesture overview)
[TapGesture]( tapgesture)
[LongPressGesture]( longpressgesture)
[DragGesture]( draggesture)
[MagnifyGesture (iOS 17+)]( magnifygesture ios 17)
[RotateGesture (iOS 17+)]( rotategesture ios 17)
[Gesture Composition]( gesture composition)
[ @GestureState ]( gesturestate)
[Adding Gestures to Views]( adding gestures to views)
[Custom Gesture Protocol]( custom gesture protocol)
[Common Mistakes]( common mistakes)
[Review Checklist]( review checklist)
[References]( references)
Gesture Overview
Gesture Type Value Since
TapGesture Discrete Void iOS 13
LongPressGesture Discrete Bool iOS 13
DragGesture Continuous DragGesture.Value iOS 13
MagnifyGesture Continuous MagnifyGesture.Value iOS 17
RotateGesture Continuous RotateGesture.Value iOS 17
SpatialTapGesture Discrete SpatialTapGesture.Value iOS 16
Discrete gestures fire once ( .onEnded ). Continuous gestures stream
updates ( .onChanged , .onEnded , .updating ).
TapGesture
Recognizes one or more taps. Use the count parameter for multi tap.
LongPressGesture
Succeeds after the user holds for minimumDuration . Fails if finger moves
beyond maximumDistance .
With visual feedback via @GestureState + .updating() :
Shorthand: .onLongPressGesture(minimumDuration:perform:onPressingChanged:) .
DragGesture
Tracks finger movement. Value provides startLocation , location ,
translation , velocity , and predictedEndTranslation .
DragGesture.Value.velocity is available with DragGesture from iOS 13+;
do not confuse it with iOS 17+ gesture types such as MagnifyGesture and
RotateGesture .
Configure minimum distance and coordinate space:
MagnifyGesture (iOS 17+)
Replaces the deprecated MagnificationGesture . Tracks pinch to zoom scale.
RotateGesture (iOS 17+)
RotateGesture is the newer alternative to RotationGesture . Tracks two finger rotation angle.
For persisted, clamped magnification and combined rotation examples, load
[references/gesture patterns.md](references/gesture patterns.md).
Gesture Composition
.simultaneously(with:) — both gestures recognized at the same time
The value is SimultaneousGesture.Value with .first and .second optionals.
.sequenced(before:) — first must succeed before second begins
.exclusively(before:) — only one succeeds (first has priority)
@GestureState
@GestureState is a property wrapper that automatically resets to its
initial value when the gesture ends. Use for transient feedback; use @State
for values that persist.
Custom reset with animation: @GestureState(resetTransaction: Transaction(animation: .spring))
Adding Gestures to Views
Three modifiers control gesture priority in the view hierarchy:
Modifier Behavior
.gesture() Lower precedence than gestures already defined by the view or its children.
.highPriorityGesture() Added gesture takes precedence over existing gestures.
.simultaneousGesture() Added gesture processes at the same priority as existing gestures.
Use .gesture(parentTap) for the default lower precedence parent gesture, or
.highPriorityGesture(parentTap) when the added parent gesture should win.
GestureMask
Control which gestures participate when using .gesture( :including:) :
Custom Gesture Protocol
Create reusable gestures by conforming to Gesture :
Wrap in a View extension for ergonomic API:
Common Mistakes
1. Misreading parent/child gesture precedence
Do not assume a parent .gesture() overrides child gestures. Choose the
relationship explicitly as shown in [Adding Gestures to Views]( adding gestures to views).
2. Using @State instead of @GestureState for transient state
Use @GestureState for values that should reset when recognition ends; keep
persistent results in @State . See [ @GestureState ]( gesturestate).
3. Not using .updating() for intermediate feedback
4. Using deprecated gesture types on iOS 17+
5. Heavy computation in onChanged
6. Using onTapGesture for actions that should be a Button
Reserve onTapGesture for multi tap ( count: 2+ ), tap location dependent
behavior, or adding tap recognition to non interactive content that already
has appropriate accessibility traits.
Review Checklist
[ ] Correct gesture type: MagnifyGesture / RotateGesture (not deprecated Magnification / Rotation variants)
[ ] @GestureState used for transient values that should reset; @State for persisted values
[ ] .updating() provides intermediate visual feedback during continuous gestures
[ ] Parent/child conflicts resolved with .highPriorityGesture() or .simultaneousGesture()
[ ] onChanged closures are lightweight — no heavy computation every frame
[ ] Composed gestures use correct combinator: simultaneously , sequenced , or exclusively
[ ] Persisted scale/rotation clamped to reasonable bounds in onEnded
[ ] Custom Gesture conformances return a gesture body; use AnyGesture<Value when mapping to a custom Value
[ ] Gesture driven animations use .spring or similar for natural deceleration
[ ] GestureMask considered when mixing gestures across view hierarchy levels
[ ] onTapGesture only used where count 1 , tap location, or coordinate space matters — plain single tap actions use Button instead
References
Read [references/gesture patterns.md](references/gesture patterns.md) when the task needs full drag to reorder, pinch to zoom, combined rotate+scale, velocity/projection, sequenced gesture state machine, or gesture specific UIKit interop examples.
[Gesture protocol](https://sosumi.ai/documentation/swiftui/gesture)
[TapGesture](https://sosumi.ai/documentation/swiftui/tapgesture)
[LongPressGesture](https://sosumi.ai/documentation/swiftui/longpressgesture)
[DragGesture](https://sosumi.ai/documentation/swiftui/draggesture)
[DragGesture.Value.velocity](https://sosumi.ai/documentation/swiftui/draggesture/value/velocity)
[MagnifyGesture](https://sosumi.ai/documentation/swiftui/magnifygesture)
[RotateGesture](https://sosumi.ai/documentation/swiftui/rotategesture)
[GestureState](https://sosumi.ai/documentation/swiftui/gesturestate)
[Composing SwiftUI gestures](https://sosumi.ai/documentation/swiftui/composing swiftui gestures)
[Adding interactivity with gestures](https://sosumi.ai/documentation/swiftui/adding interactivity with gestures)