How it works
MagnificationGesture recognizes a pinch — two fingers moving toward or away from each other — and reports the change as a relative scale factor. It gives you a continuous magnification value (1.0 at the moment the pinch begins) so you can drive zoom-style interactions without tracking individual touches yourself. Reach for it whenever content should grow or shrink under the user's fingers, such as photos, maps, or any view that benefits from pinch-to-zoom.
Construct the recognizer with MagnificationGesture()
The parameterless initializer creates a gesture that interprets a two-finger pinch as a magnification. As a value type conforming to Gesture, it carries no state of its own — you build one inline, as in
MagnificationGesture(), and attach callbacks to observe it.Attach it to a view with gesture(_:)
A gesture does nothing until it is bound to a view's interaction region. The
.gesture(...)modifier installs the recognizer on whatever it modifies; here it wraps the pinch around theImage, so the pinch is only recognized over that view.Track the live scale with onChanged
onChangedfires repeatedly as the pinch progresses, handing you the gesture's current value — the running scale factor relative to the gesture's start. The closure receivesvalueand pushes it into state withscale = value, so every incremental pinch update is captured.Apply the value with scaleEffect(_:) and @State
Because the magnification value is just a number, you feed it into a visual modifier to make the change visible. The
@State private var scaleholds the factor and.scaleEffect(scale)resizes theImageaccordingly, so the view grows and shrinks in step with the pinch.
onChanged body to scale = max(0.5, min(value, 3)) so the magnification is clamped, revealing how MagnificationGesture's raw value can be bounded before it drives the zoom.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 MagnificationGestureDemo: View {
@State private var scale: CGFloat = 1.5
var body: some View {
VStack(spacing: 16) {
Text("Pinch to zoom")
.font(.headline)
Image(systemName: "photo")
.font(.system(size: 80))
.scaleEffect(scale)
.gesture(
MagnificationGesture()
.onChanged { value in
scale = value
}
)
Text("Scale: \(scale, specifier: "%.1f")x")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding()
}
}