SwiftUI 为我们提供了许多处理视图的手势,并且很好地消除了大部分艰苦的工作
点击 onTapGesture
Text("xxx")
.onTapGesture {
//...
}
可以向它们传递一个参数count,让它们处理双击、三击等等,就像这样:
.onTapGesture(count: 2) {
}
长按 onLongPressGesture
Text("Hello, World!")
.onLongPressGesture {
}
可以指定按下的最短持续时间,以便您的操作关闭仅在经过特定秒数后触发
.onLongPressGesture(minimumDuration: 2) {
}
可以添加第二个闭包,该闭包会在手势状态发生更改时触发。
Text("Hello, World!")
.onLongPressGesture(minimumDuration: 1) {
} onPressingChanged: { inProgress in
}
对于更高级的手势,您应该将gesture()修饰符与以下手势结构之一结合使用:DragGesture、LongPressGesture、MagnifyGesture、RotateGesture和TapGesture。这些通常都有特殊的修饰符onEnded(),onChanged()您可以使用它们在手势进行中 或完成 时采取行动。
捏合
将放大手势附加到视图,以便捏合和张开可以放大或缩小视图。这可以通过创建两个@State属性来存储缩放量,在scaleEffect()修改器内使用它,然后在手势中设置这些值来完成,
struct ContentView: View {
@State private var currentAmount = 0.0
@State private var finalAmount = 1.0
var body: some View {
Text("Hello, World!")
.scaleEffect(finalAmount + currentAmount)
.gesture(
MagnifyGesture()
.onChanged { value in
currentAmount = value.magnification - 1
}
.onEnded { value in
finalAmount += currentAmount
currentAmount = 0
}
)
}
}
旋转
struct ContentView: View {
@State private var currentAmount = Angle.zero
@State private var finalAmount = Angle.zero
var body: some View {
Text("Hello, World!")
.rotationEffect(currentAmount + finalAmount)
.gesture(
RotateGesture()
.onChanged { value in
currentAmount = value.rotation
}
.onEnded { value in
finalAmount += currentAmount
currentAmount = .zero
}
)
}
}
手势的优先级
当您有两个或多个可能同时识别的手势时,例如,如果您将一个手势附加到视图,并将相同的手势附加到其父级。
VStack {
Text("Hello, World!")
.onTapGesture {
}
}
.onTapGesture {
}
在这种情况下,SwiftUI 将始终优先考虑 子视图 的手势 。
如果您想更改此设置,可以使用highPriorityGesture()修饰符强制触发父级的手势
VStack {
Text("Hello, World!")
.onTapGesture {
}
}
.highPriorityGesture(
TapGesture()
.onEnded {
}
)
或者,您可以使用simultaneousGesture()修饰符告诉 SwiftUI 您希望父手势和子手势同时触发
VStack {
Text("Hello, World!")
.onTapGesture {
}
}
.simultaneousGesture(
TapGesture()
.onEnded {
}
)
手势序列
SwiftUI 允许我们创建手势序列,其中一个手势只有在另一个手势首先成功时才会激活 。示例:您可以在其中拖动一个圆圈,但前提是先长按它
禁止交互
Circle()
.fill(.red)
.frame(width: 300, height: 300)
.onTapGesture {
print("Circle tapped!")
}
.allowsHitTesting(false)
堆栈的交互
默认情况下,当点击堆栈间隔符时,SwiftUI 不会触发操作
VStack {
Text("Hello")
Spacer().frame(height: 100)
Text("World")
}
.onTapGesture {
print("VStack tapped!")
}
如果你运行它,你会发现你可以点击“Hello”标签和“World”标签,但不能点击之间的空格。
使用contentShape(.rect) ,VStack那么堆栈的整个区域都变得可点击,包括间隔符
VStack {
Text("Hello")
Spacer().frame(height: 100)
Text("World")
}
.contentShape(.rect)
.onTapGesture {
print("VStack tapped!")
}