30天学会Swift-25:SwiftUI-手势
SwiftUI手势处理指南 本文介绍了SwiftUI中常用的手势识别功能,包括点击、拖动、缩放和旋转手势的基本用法。主要内容包括: 点击手势(onTapGesture)的单次和多次点击实现 拖动手势(DragGesture)的基本使用和状态信息 缩放手势(MagnificationGesture)的实现方法 旋转手势(RotationGesture)的应用 三种手势组合方式:同时识别(simult
·
学习目标
- 理解SwiftUI中手势识别器的基本概念。
- 掌握如何使用
onTapGesture
处理点击手势。 - 学习如何使用
DragGesture
处理拖动手势。 - 掌握如何使用
MagnificationGesture
处理缩放手势。 - 掌握如何使用
RotationGesture
处理旋转手势。 - 了解手势组合(
simultaneously
、sequenced
、exclusively
)和手势状态。
学习内容
1. 手势识别器基础
SwiftUI通过手势识别器(Gesture Recognizers
)来响应用户的交互。你可以将一个或多个手势识别器附加到任何视图上。
2. onTapGesture
(点击手势)
用于检测单次或多次点击。
2.1 单次点击
struct TapGestureExample: View {
@State private var message = "Tap me!"
var body: some View {
Text(message)
.font(.largeTitle)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
.onTapGesture {
message = "Tapped!"
}
}
}
2.2 多次点击
struct DoubleTapGestureExample: View {
@State private var tapCount = 0
var body: some View {
Text("Tap Count: \(tapCount)")
.font(.largeTitle)
.padding()
.onTapGesture(count: 2) {
tapCount += 1
}
}
}
3. DragGesture
(拖动手势)
用于检测视图的拖动操作,并提供拖动过程中的位置和速度信息。
3.1 基本拖动
struct DragGestureExample: View {
@State private var offset = CGSize.zero
var body: some View {
Circle()
.fill(Color.red)
.frame(width: 100, height: 100)
.offset(offset) // 应用偏移量
.gesture(
DragGesture()
.onChanged { gesture in
offset = gesture.translation // 实时更新偏移量
}
.onEnded { gesture in
// 拖动结束时可以做一些处理,例如回到原位或吸附到某个位置
// offset = .zero // 拖动结束后回到原位
print("Drag ended at: \(gesture.location)")
}
)
}
}
3.2 拖动状态
DragGesture
的onChanged
和onEnded
闭包会接收一个DragGesture.Value
参数,其中包含:
location
: 当前手势在视图中的位置。startLocation
: 手势开始时的位置。translation
: 从开始位置到当前位置的累积偏移量。predictedEndLocation
: 预测手势结束时的位置。velocity
: 手势的速度。
4. MagnificationGesture
(缩放手势)
用于检测捏合缩放操作。
struct MagnificationGestureExample: View {
@State private var scale: CGFloat = 1.0
@State private var lastScale: CGFloat = 1.0
var body: some View {
Image(systemName: "heart.fill")
.font(.system(size: 100))
.foregroundColor(.pink)
.scaleEffect(scale)
.gesture(
MagnificationGesture()
.onChanged { value in
scale = lastScale * value // 实时更新缩放比例
}
.onEnded { value in
lastScale = scale // 记录最终缩放比例
}
)
}
}
5. RotationGesture
(旋转手势)
用于检测两指旋转操作。
struct RotationGestureExample: View {
@State private var angle: Angle = .zero
@State private var lastAngle: Angle = .zero
var body: some View {
Rectangle()
.fill(Color.green)
.frame(width: 150, height: 150)
.rotationEffect(angle)
.gesture(
RotationGesture()
.onChanged { value in
angle = lastAngle + value // 实时更新旋转角度
}
.onEnded { value in
lastAngle = angle // 记录最终旋转角度
}
)
}
}
6. 手势组合
SwiftUI提供了三种手势组合方式:
6.1 simultaneously(with:)
(同时识别)
允许两个手势同时被识别。
struct SimultaneousGestureExample: View {
@State private var offset = CGSize.zero
@State private var scale: CGFloat = 1.0
var body: some View {
Image(systemName: "star.fill")
.font(.system(size: 100))
.offset(offset)
.scaleEffect(scale)
.gesture(
DragGesture()
.onChanged { offset = $0.translation }
.simultaneously(with: MagnificationGesture()
.onChanged { scale = $0 }
)
)
}
}
6.2 sequenced(before:)
(顺序识别)
一个手势成功后,才开始识别另一个手势。
struct SequencedGestureExample: View {
@State private var message = "Long press then drag"
var body: some View {
Text(message)
.font(.title)
.padding()
.gesture(
LongPressGesture(minimumDuration: 1)
.onEnded { _ in
message = "Long pressed! Now drag."
}
.sequenced(before: DragGesture()
.onChanged { _ in
message = "Dragging..."
}
.onEnded { _ in
message = "Drag ended."
}
)
)
}
}
6.3 exclusively(before:)
(排他识别)
如果第一个手势被识别,则第二个手势不会被识别;否则,尝试识别第二个手势。
struct ExclusiveGestureExample: View {
@State private var message = "Tap or Long Press"
var body: some View {
Text(message)
.font(.title)
.padding()
.gesture(
TapGesture()
.onEnded { _ in
message = "Tapped!"
}
.exclusively(before: LongPressGesture(minimumDuration: 1)
.onEnded { _ in
message = "Long Pressed!"
}
)
)
}
}
7. 手势状态
手势通常有三种状态:
inactive
:手势未被激活。active
:手势正在被识别(例如,拖动正在进行中)。ended
:手势识别完成。
你可以通过@GestureState
属性包装器来跟踪手势的瞬时状态,当手势结束时,@GestureState
变量会自动重置。
struct GestureStateExample: View {
@GestureState private var isDetectingLongPress = false
@State private var feedback = ""
var body: some View {
Text(feedback)
.font(.largeTitle)
.padding()
.background(isDetectingLongPress ? Color.red : Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
.gesture(
LongPressGesture(minimumDuration: 1)
.updating($isDetectingLongPress) { currentState, gestureState, transaction in
gestureState = currentState // 当长按开始时,gestureState变为true
}
.onEnded { _ in
feedback = "Long Press Detected!"
}
)
}
}
实践练习
- 可拖动的图片:
- 创建一个
Image
视图,使其可以通过拖动手势在屏幕上自由移动。 - 尝试在拖动结束后,让图片平滑地回到屏幕中心。
- 创建一个
- 图片缩放与旋转:
- 创建一个
Image
视图,使其可以通过捏合手势进行缩放,并通过两指旋转手势进行旋转。 - 确保缩放和旋转可以同时进行。
- 创建一个
- 自定义手势组合:
- 创建一个视图,当用户先长按(1秒)然后拖动时,显示不同的文本提示。
- 如果用户只是长按,则显示“长按成功”,不进行拖动。
思考题
@GestureState
和普通的@State
在手势处理中的区别是什么?为什么@GestureState
在某些场景下更优?- 如何处理手势冲突,例如一个视图既有点击手势又有拖动手势?
- 在实际应用中,你会如何设计复杂的用户手势交互?

为武汉地区的开发者提供学习、交流和合作的平台。社区聚集了众多技术爱好者和专业人士,涵盖了多个领域,包括人工智能、大数据、云计算、区块链等。社区定期举办技术分享、培训和活动,为开发者提供更多的学习和交流机会。
更多推荐
所有评论(0)