How it works
Manipulable describes how a view participates in direct, gesture-driven manipulation — letting people grab, move, rotate, and scale a piece of content with their hands or a pointer. You opt a view into this behavior with the manipulable() family of modifiers, which install the combined move/rotate/scale gesture set with sensible defaults so you don't wire up each spatial gesture by hand. Reach for it when you want content to feel like a physical object the user can pick up and reposition, most commonly with 3D models, while still letting the system manage hit-testing, inertia, and the snap-back to the resting state.
Make a view manipulable with manipulable()
Calling
.manipulable()on a view turns it into a target for the unified manipulation gesture, enabling all available operations — translation, rotation, and scale — at once. In the example, the modifier is applied to the styledImage(systemName: "photo")so that this single view becomes the thing the user can grab; the rest of the chain (resizable(),scaledToFit(),frame,foregroundStyle) only prepares its appearance before manipulation is attached.Attach it where the content is fully laid out
Order matters in a modifier chain:
manipulable()should sit after the modifiers that establish the view's size and shape, because it manipulates whatever it wraps. Here it follows.frame(width: 120, height: 120)and.foregroundStyle(.blue), so the 120-point square is the region the gesture acts on, and the later.padding()simply reserves room around that manipulable region.Rely on the default return-to-rest behavior
By default a manipulable view tracks the active gesture and then animates back to its original transform when the interaction ends, so the layout you authored is never permanently disturbed. The bare
.manipulable()call in the example takes this default path — the image springs back to its starting position and scale after each drag, rotate, or pinch.Restrict the gesture set or track state with the configured forms
When you need finer control, the configured initializers let you narrow which operations are allowed and observe the result instead of accepting the all-on default.
manipulable(using:)takes a manipulation configuration so you can permit, say, only rotation and translation, whilemanipulable(transform:)binds the live transform so you can retain the position where the user left the object rather than snapping back.
.manipulable() to .manipulable(transform: $transform) (with a @State var transform) so the photo image keeps the position and scale you leave it in instead of springing back to the 120×120 frame.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.
struct ManipulableDemo: View {
var body: some View {
Image(systemName: "photo")
.resizable()
.scaledToFit()
.frame(width: 120, height: 120)
.foregroundStyle(.blue)
.manipulable()
.padding()
}
}