SwiftUI Gestures DragGesture
SwiftUI Gestures: DragGesture
Track finger movement and update view position or state in response to a DragGesture.
Syntax
Drag: Attach DragGesture() and handle .onChanged/.onEnded.
Apply translation via .offset.
Drag to Move
Drag the label to move it around. Releasing snaps it back using a spring animation.
Example
import SwiftUI
struct DragDemo: View {
@State private var offset: CGSize = .zero
var body: some View {
Text("Drag me")
.padding(12)
.background(.blue.opacity(0.1))
.cornerRadius(8)
.offset(offset)
.gesture(
DragGesture()
.onChanged { value in offset = value.translation }
.onEnded { _ in withAnimation(.spring()) { offset = .zero } }
)
}
}
import SwiftUI
struct ContentView: View {
var body: some View { DragDemo() }
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
In the example above, the label is dragged and released.
The .onEnded handler snaps it back using a spring animation.
Constrain Drag Within Bounds
Clamp the drag translation so the view stays inside a container.
Example
import SwiftUI
struct DragBoundsDemo: View {
@State private var offset: CGSize = .zero
let limit: CGFloat = 120
func clamp(_ v: CGFloat) -> CGFloat { min(max(v, -limit), limit) }
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 12)
.stroke(.gray.opacity(0.4), lineWidth: 1)
.frame(width: 280, height: 160)
Circle()
.fill(.blue.opacity(0.2))
.frame(width: 44, height: 44)
.offset(x: offset.width, y: offset.height)
.gesture(
DragGesture()
.onChanged { value in
offset = CGSize(width: clamp(value.translation.width), height: clamp(value.translation.height))
}
.onEnded { _ in withAnimation(.spring()) { offset = .zero } }
)
}
.padding()
}
}
import SwiftUI
struct ContentView: View {
var body: some View { DragBoundsDemo() }
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
In the example above, the circle is dragged and released.
The .onEnded handler snaps it back using a spring animation.