Skip to content
Development
Skill

/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

From plugin
swift-ios-skills
98186 skills1 MCP
Install
$ npx -y skills add dpearson2699/swift-ios-skills --skill swiftui-gestures --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/swiftui-gestures

Context preview

The summary Claude sees to decide when to auto-load this skill.

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

SKILL.md

swiftui-gestures.SKILL.md
name: swiftui-gestures
description: "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 simultaneousGesture, building custom Gesture protocol conformances, or migrating from deprecated MagnificationGesture to MagnifyGesture or using the newer RotateGesture."

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.

// Single, double, and triple tap
TapGesture()            .onEnded { tapped.toggle() }
TapGesture(count: 2)    .onEnded { handleDoubleTap() }
TapGesture(count: 3)    .onEnded { handleTripleTap() }

// Shorthand modifier
Text("Tap me").onTapGesture(count: 2) { handleDoubleTap() }

LongPressGesture

Succeeds after the user holds for `minimumDuration`. Fails if finger moves beyond `maximumDistance`.

// Basic long press (0.5s default)
LongPressGesture()
    .onEnded { _ in showMenu = true }

// Custom duration and distance tolerance
LongPressGesture(minimumDuration: 1.0, maximumDistance: 10)
    .onEnded { _ in triggerHaptic() }

With visual feedback via `@GestureState` + `.updating()`:

@GestureState private var isPressing = false

Circle()
    .fill(isPressing ? .red : .blue)
    .scaleEffect(isPressing ? 1.2 : 1.0)
    .gesture(
        LongPressGesture(minimumDuration: 0.8)
            .updating($isPressing) { current, state, _ in state = current }
            .onEnded { _ in completedLongPress = true }
    )

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`.

@State private var offset = CGSize.zero

RoundedRectangle(cornerRadius: 16)
    .fill(.blue)
    .frame(width: 100, height: 100)
    .offset(offset)
    .gesture(
        DragGesture()
            .onChanged { value in offset = value.translation }
            .onEnded { _ in withAnimation(.spring) { offset = .zero } }
    )

Configure minimum distance and coordinate space:

DragGesture(minimumDistance: 20, coordinateSpace: .global)

MagnifyGesture (iOS 17+)

Replaces the deprecated `MagnificationGesture`. Tracks pinch-to-zoom scale.

@GestureState private var magnifyBy = 1.0

Image("photo")
    .resizable().scaledToFit()
    .scaleEffect(magnifyBy)
    .gesture(
        MagnifyGesture()
            .updating($magnifyBy) { value, state, _ in
                state = value.magnification
            }
    )

RotateGesture (iOS 17+)

`RotateGesture` is the newer alternative to `RotationGesture`. Tracks two-finger rotation angle.

@State private var angle = Angle.zero

Rectangle()
    .fill(.blue).frame(width: 200, height: 200)
    .rotationEffect(angle)
    .gesture(
        RotateGesture(minimumAngleDelta: .degrees(1))
            .onChanged { value in angle = value.rotation }
    )

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

let magnify = MagnifyGesture()
    .onChanged { value in scale = value.magnification }

let rotate = RotateGesture()
    .onChanged { value in angle = value.rotation }

Image("photo")
    .scaleEffect(scale)
    .rotationEffect(angle)
    .gesture(magnify.simultaneously(with: rotate))

The value is `SimultaneousGesture.Value` with `.first` and `.second` optionals.

`.sequenced(before:)` — first must succeed before second begins

let longPressBeforeDrag = LongPressGesture(minimumDuration: 0.5)
    .sequenced(before: DragGesture())
    .onEnded { value in
        guard case .seco
Read more
Ships withswift-ios-skills

86 agent skills optimized for iOS 26+ development with Swift 6.3 and modern Apple frameworks.

Get the whole plugin
Stats
981
Stars
50
Forks
Active
Maintenance
Python
Language
9d ago
Last commit
5mo ago
Created

Repo: dpearson2699/swift-ios-skills

Other skills on swift-ios-skills.