SwiftUI为我们提供了处理视图的许多手势,并且在消除大部分辛苦工作方面做得非常出色,因此我们可以专注于程序的重要的部分。最常见的是onTapGesture(),这很容易,但是还有其他几个,还有一些有趣的方式可以将手势组合在一起,值得一试。
任何SwiftUI视图都可以使用手势识别器,而这些手势识别器又可以连接将在识别器激活时运行的闭包。 下面将介绍一个简单的gesture。例如,这将创建一个图像,该图像在每次点击时都会变小:
Text("ireland")
.scaleEffect(scale)
.gesture(
TapGesture()
.onEnded { _ in
scale -= 0.1//点击一次减0.1
}
)
gesture可以将手势附加到任何视图,其优先级低于视图定义的手势。
符合gesture协议的有下列手势(iOS 13.0以上、macOS 10.15以上、Mac Catalyst 13.0以上、watchOS 6.0+):
SwiftUI提供2个快速应用于视图2个带on的基本手势,一个是点击(onTapGesture),另一个是长按(onLongPressGesture) 。
1、onTapGesture 识别一个或多个轻击的手势。添加一个在视图识别点击手势时执行的操作。
Text("点我试试!")
.onTapGesture{
print("单击")
}
.onTapGesture(count: 2) {
print("双击")
}
小TIPS:可以ButtonStyle修饰达到与按钮一样的视觉效果哦~
2、onLongPressGesture 当用户执行长按时成功的手势。
Text("长按我不放!")
.onLongPressGesture {
print("用户长按操作!")
}
像轻击onTapGesture手势一样,长按手势也可以自定义。例如,您可以指定印刷的最短时间,因此仅在经过特定的秒数后才触发操作关闭。例如,这将仅在两秒钟后触发:
Text("按我5秒才能触发操作!")
.onLongPressGesture(minimumDuration: 5) {
print("长按5秒,停止运动!")//类似Keep的结束跑步
}
如果想监听长按的开始与结束,可以使用下面的方法:
Text("监听长按期间的事件!")
.onLongPressGesture(minimumDuration: 5, pressing: { inProgress in
print( inProgress ? "用户正在长按中~" : "用户长按结束")
}) {
print("长按成功")
}
上面已介绍了长按与点击操作,因为比较简单,所以这里将不再赘述,下面将介绍几个经常会用到的基本手势的使用:
1、DragGesture 拖动动作,随着拖动事件序列的更改而调用动作。
初始化(minimumDistance: CGFloat, coordinateSpace: coordinateSpace),创建一个拖动手势,使其在手势成功之前具有最小的拖动距离和手势所在的坐标空间。
struct ContentView: View {
@State private var dragOffset = CGSize.zero
var body: some View {
VStack {
Text("rome")
.offset(dragOffset)//视图偏移
.gesture(
DragGesture()
.onChanged { gesture in
dragOffset = gesture.translation//将拖动位置赋值给偏移量
}
.onEnded { gesture in
dragOffset = .zero//拖动结束后位置还原
}
)
}
}
}
关于拖动手势下面的示例中将有更多的代码应用。
2、MagnificationGesture 识别放大运动并跟踪放大的手势。
添加一个放大手势到一个圆上,当用户执行这个手势时,可以改变它的大小:
struct ContentView: View {
//GestureState在用户执行手势时更新属性,并在手势结束时将属性重置回初始状态。
@GestureState var magnifyBy:CGFloat = 1.0 //定义一个状态跟踪值
//Gesture 将一系列事件匹配到一个手势,并为其每个状态返回一个值流。
var magnification: some Gesture {
MagnificationGesture()
//当手势的值改变时利用updating更新提供的手势状态属性。
.updating($magnifyBy) { currentState, gestureState, transaction in
gestureState = currentState
}
}
var body: some View {
Circle()
.frame(width: 100 * magnifyBy,
height: 100 * magnifyBy,
alignment: .center)
.gesture(magnification)//应用手势操作
}
}
放大手势跟踪放大事件序列的变化。要识别视图上的放大手势,创建并配置手势,然后使用手势(_:including:)修饰符将它添加到视图中。
3、RotationGesture 识别旋转运动并跟踪旋转角度的手势。
旋转手势跟踪一个旋转事件序列的变化。要识别视图上的旋转手势,创建并配置这个手势,然后使用手势(_:including:)修饰符将它添加到视图中。
给矩形添加一个旋转手势,并应用一个旋转效果:
struct ContentView: View {
@State var angle = Angle(degrees: 0.0)//形状的初始角度
var rotation: some Gesture {
RotationGesture()
.onChanged { angle in
self.angle = angle//将用户旋转的角度赋值给监听属性angle
}
}
var body: some View {
Rectangle()
.frame(width: 200, height: 200, alignment: .center)
.rotationEffect(self.angle)//通过监听属性值的变化发生角度变化
.gesture(rotation)//应用手势操作
}
}
组成Swift UI手势组合手势以创建复杂的交互。上面代码里已看到 gesture 将组合的手势应用给视图,下面使用组合的手势实现一个可以拖动的红色圆圈:
struct ContentView: View {
@State private var offset = CGSize.zero//拖了多远
@State private var isDragging = false//是否可以被拖走
var body: some View {
// 定义一个在移动时更新偏移量和isdrag
let dragGesture = DragGesture()//当拖动事件序列改变时调用动作的拖动动作。
.onChanged { value in self.offset = value.translation }//拖动后更新偏移量
.onEnded { _ in
withAnimation {
self.offset = .zero//位置还原,注释这行圈圈将停留在被拖到的位置
self.isDragging = false//拖动状态还原为不能拖走
}
}
// 当用户长按后isDragging变成可拖动状态
let pressGesture = LongPressGesture()
.onEnded { value in
withAnimation {
self.isDragging = true
}
}
// 用户必须长按后才能拖动的组合手势
let combined = pressGesture.sequenced(before: dragGesture)
// 一个64x64的圆,当它被拖动时,它会放大,将它的偏移量设置为我们从拖动手势得到的任何东西,并使用我们的组合手势
Circle()//仔细看,上面都是let,这里才是视图
.fill(Color.red)
.frame(width: 64, height: 64)
.scaleEffect(isDragging ? 1.5 : 1)//isDragging可拖动状态时放大1.5倍
.offset(offset)//偏移位置
.gesture(combined)//将组合的手势应用给Circle视图
}
}
用户需要将其中一个手势完成后才能使用另一个手势(长按成功后才会变为活动状态)。这需要更多的思考,因为手势需要能够相互引用,因此您不能仅将它们直接附加到视图。
对于更高级的手势,你应该使用gesture()修饰符手势结构之一:DragGesture,LongPressGesture,MagnificationGesture,RotationGesture,和TapGesture。这些都具有通常onEnded()和经常onChanged()使用的特殊修饰符,并且您可以在手势进行中(for onChanged())或完成中(for onEnded())时使用它们进行操作。
例如,我们可以将放大手势附加到视图上,以便捏入和缩小可以放大和缩小视图。可以通过创建两个@State属性来存储缩放比例scaleEffect(),然后在修饰符中使用该属性,然后在手势中设置这些值来完成此操作,如下所示:
//模拟器里需要按住OPT键拖动看效果
struct ContentView: View {
@State private var currentAmount: CGFloat = 0//目前的数量
@State private var finalAmount: CGFloat = 1//最终的数量
var body: some View {
Text("我是一个可旋转的文本内容!")
//scaleEffect 在水平和垂直方向上,相对于一个锚点,按给定的数量缩放这个视图的渲染输出。
.scaleEffect(finalAmount + currentAmount)
//gesture 将手势附加到视图,其优先级低于视图定义的手势。
.gesture(
//识别放大动作并跟踪放大量的手势。
MagnificationGesture()
//将改变的数量交给监听属性
.onChanged { amount in
self.currentAmount = amount - 1
}
//将结束后最终数量finalAmount交给监听忏悔
.onEnded { amount in
self.finalAmount += self.currentAmount
self.currentAmount = 0//回到初始状态
}
)
}
}
可以使用完全相同的方法来旋转视图RotationGesture,只是现在我们使用rotationEffect()修饰符:
//按住键盘上的OPT(ALT)键盘测试放大旋转
struct ContentView: View {
@State private var currentAmount: Angle = .degrees(0)//目前的角度
@State private var finalAmount: Angle = .degrees(0)//最终角度
var body: some View {
Text("我是通过角度旋转的文字内容!")
.rotationEffect(currentAmount + finalAmount)
.gesture(
RotationGesture()
.onChanged { angle in
self.currentAmount = angle//将改后的弧度或角度交给监听属性
}
.onEnded { angle in
self.finalAmount += self.currentAmount
self.currentAmount = .degrees(0)
}
)
}
}
当手势发生冲突时,事情开始变得更加有趣了–当您同时识别两个或多个手势时,例如您将一个手势附加到视图上,并将同一手势附加到其父视图上。
1、手势的优先权
例如,这会将on附加onTapGesture()到文本视图及其父视图:
VStack {
Text("我离你最近,我具有点击优先权!")
.onTapGesture {
print("文本点击(我将优先识别)")
}
}
.onTapGesture {
print("VStack 点击(我非优先)")
}
在这种情况下,SwiftUI将始终为子视图提供手势优先权,这意味着当您点击上方的文本视图时,您将看到“文本点击”。但是,如果要更改它,可以使用highPriorityGesture()修饰符来强制触发父母的手势,如下所示:
VStack {
Text("不能优先触发我的onTapGesture,你点我干嘛!!!")
.onTapGesture {
print("Text 点击(VStack做弊了~)")
}
}
//highPriorityGesture将一个手势附加到视图,其优先级高于视图所定义的手势。
.highPriorityGesture(
TapGesture()
.onEnded { _ in
print("VStack 点击(我有优先权,因为有highPriorityGesture加持~)")
}
)
2、SimultaneousGesture 可以包含两个手势并可以同时触发,而两个手势都不在另一个手势之前。您可以使用simultaneousGesture()修饰符告诉SwiftUI您希望同时触发父手势和子视图的手势,如下所示:
VStack {
Text("Hello, World!")
.onTapGesture {
print("Text 点击(我将VStack同时输出)")
}
}
//将一个手势附加到视图,以便与视图定义的手势同时处理。
.simultaneousGesture(
TapGesture()
.onEnded { _ in
print("VStack 点击(虽然打印有先后,但其实我们是同时输出的)")
}
)
这将同时打印“文字被点击”和“ VStack被点击”。
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/133
《【SwiftUI基础篇】19 一文读懂手势操作,常用手势监听与触发应用详解》的网友评论(0)