SwiftUI Gestures 手勢操作教學
除了基本的點擊 (Tap),使用者的手指還可以做出拖曳、捏合縮放、旋轉等動作。SwiftUI 提供了強大的 Gesture API 來識別這些操作。
點擊手勢 (TapGesture)
雖然 Button 已經有點擊功能,但 onTapGesture 可以讓任何 View 變成可點擊。
Image("photo")
.onTapGesture(count: 2) { // 雙擊
print("圖片被雙擊了")
}
長按手勢 (LongPressGesture)
Text("長按我")
.onLongPressGesture(minimumDuration: 1.0) {
print("已長按 1 秒")
}
拖曳手勢 (DragGesture)
用於實作拖放 (Drag & Drop) 或滑動卡片效果。
@State private var offset = CGSize.zero
@State private var isDragging = false
Image("card")
.offset(offset)
.gesture(
DragGesture()
.onChanged { value in
offset = value.translation // 跟隨手指移動
isDragging = true
}
.onEnded { value in
// 預測慣性停止點 (Tossing)
// value.predictedEndTranslation 可以用來判斷滑動的力道
withAnimation {
offset = .zero // 放開後彈回原位
isDragging = false
}
}
)
縮放手勢 (MagnificationGesture)
用於捏合縮放圖片或地圖。
@State private var currentScale: CGFloat = 1.0
@State private var finalScale: CGFloat = 1.0
Image("map")
.scaleEffect(finalScale * currentScale)
.gesture(
MagnificationGesture()
.onChanged { value in
currentScale = value // 手指正在捏合時的倍率變換
}
.onEnded { value in
finalScale *= value // 結束後保存倍率
currentScale = 1.0 // 重置當前倍率
}
)
旋轉手勢 (RotationGesture)
@State private var angle = Angle.zero
Image("compass")
.rotationEffect(angle)
.gesture(
RotationGesture()
.onChanged { value in
angle = value
}
)
組合手勢
當一個 View 有多個手勢時,我們需要決定優先順序。
同時識別 (Simultaneous)
例如同時支援縮放和旋轉(像相簿瀏覽圖片)。
let zoom = MagnificationGesture().onChanged { ... }
let rotate = RotationGesture().onChanged { ... }
let combined = zoom.simultaneously(with: rotate)
Image("photo")
.gesture(combined)
順序識別 (Sequenced)
例如:必須先長按,才能開始拖曳(避免誤觸)。
// 1. 定義狀態:是否處於長按準備拖曳的狀態
@State private var isDraggable = false
@State private var offset = CGSize.zero
// 2. 定義手勢
let longPress = LongPressGesture(minimumDuration: 0.5)
.onEnded { _ in isDraggable = true }
let drag = DragGesture()
.onChanged { value in
if isDraggable { offset = value.translation }
}
.onEnded { _ in
isDraggable = false
offset = .zero
}
// 3. 組合:LongPress 之後接 Drag
let sequence = longPress.sequenced(before: drag)
Circle()
.fill(isDraggable ? .green : .blue)
.offset(offset)
.gesture(sequence)
排他識別 (Exclusive)
exclusively(before:) 表示如果第一個手勢成功,就忽略第二個。
掌握手勢操作,你可以創造出更符合直覺且有趣的交互體驗。