TechnologiesSwiftUI

RotateGesture struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A gesture that recognizes a rotation motion and tracks the angle of the

How it works

RotateGesture is a gesture that recognizes a rotation motion as the user moves two fingers around a shared center point on a trackpad or touchscreen. As the fingers turn, it tracks the cumulative angle and reports it as an Angle value, giving you a measurement you can feed directly into a view's rotation. Reach for it whenever a view should respond to a twist — turning a knob, spinning a card, or orienting an element by hand — instead of mapping raw touch coordinates yourself.

  1. Create the gesture with RotateGesture()

    The initializer constructs a recognizer that begins tracking once a two-finger rotation is detected. You can pass a minimumAngleDelta to require a small initial turn before the gesture activates, which filters out incidental movement; calling RotateGesture() with no arguments accepts the default threshold so even slight rotations are honored.

  2. Read the angle from the gesture value

    While the gesture is active it produces a value whose rotation property is the Angle turned since the gesture started. In the example this drives state directly with angle = value.rotation, so the stored angle always reflects the current twist of the fingers rather than an absolute screen orientation.

  3. Respond to updates with onChanged

    Chaining .onChanged onto the gesture installs a closure that runs on every recognition update, receiving the latest value. This is where you apply live feedback as the user rotates; pair it with onEnded when you need to commit or snap a final position once the fingers lift.

  4. Attach it to a view with gesture(_:)

    A gesture only does work once it's bound to a view's interaction region. Here .gesture(...) attaches the configured RotateGesture to the RoundedRectangle, so rotations performed over that view are the ones it recognizes.

  5. Apply the result with rotationEffect(_:)

    RotateGesture supplies the measurement, and a view modifier consumes it. The .rotationEffect(angle) modifier reads the same angle the gesture writes, visually turning the card so it tracks the user's fingers in real time.

Try it — Add .onEnded { _ in angle = Angle(degrees: 0) } after onChanged so the card snaps back to upright the moment you release, making the difference between a live rotation and its final committed state obvious.

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.

RotateGesture.swift
struct RotateGestureDemo: View {
    @State private var angle = Angle(degrees: 30)

    var body: some View {
        VStack(spacing: 16) {
            Text("Rotate me")
            RoundedRectangle(cornerRadius: 16)
                .fill(.blue.gradient)
                .frame(width: 140, height: 140)
                .overlay(Text("\(Int(angle.degrees))°").foregroundStyle(.white).font(.title))
                .rotationEffect(angle)
                .gesture(
                    RotateGesture()
                        .onChanged { value in angle = value.rotation }
                )
        }
        .padding()
    }
}
Live preview
Rotate me \(Int(an…
Rotate me \(Int(an…
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →