SwiftUI 手势操作
基本概念
在ios中我们经常用到的手势操作有点击,长按,拖拽,缩放,旋转。在手势操作时,不同的手势有不同的触发函数,比如,点击在点击完成时触发某个函数,拖拽手势不仅仅在拖拽完成时触发函数,而在拖拽的过程中也可以触发两个函数,在这两个函数中捕捉到不同的参数。对于手势的捕获也有两种方式,我们具体的看下这两种方式
方式一,通过gesture捕获手势
我们可以给View添加一个gesture()
的装饰函数来捕捉手势,在这个函数中设定不同Gesture()
就可以捕捉到不同的手势。在捕捉到手势之后,还有3个回调函数处理不同的情况,updating(_:body)
在手势操作时被调用,这个函数需要绑定一个@GestureState
修饰的变量,这个变量在回调时被修改,但只是临时的修改,手势操作完这个变量会被修改为手势操作之前的初始化值.onChange(_:)
这个同样是在手势操作时被调用,这个函数中修改的变量在手势操作结束时被保留。onEnd()
这个函数时在手势操作成功之后调用。
缩放
我们设定一个图片缩放场景来演示缩放手势,先通过image显示一张图片,我们通过缩放手势让图片放大或者缩小。捕获的gesture是MagnificationGesture
.代码如下
@GestureState var zoom:CGFloat=1Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).scaleEffect(zoom).gesture(MagnificationGesture().updating($zoom, body: {gestureZoom,z,transaction inz=gestureZoom}))
设定一个@GestureState
修饰的变量zoom
,用来控制图片的缩放比例。在这段代码中gestureZoom
是我们做缩放手势时的缩放比例,z
就是zoom
,我们将gestureZoom
的数值赋值过去,图片就放大/缩小,当我们手势结束时,zoom
就变成1。图片回到原先大小。
@State var zoom:CGFloat=1
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).scaleEffect(zoom).gesture(MagnificationGesture().onChanged({z in zoom=z}))
这段代码,我们将zoom
用@State
修饰,onChange
中z
是缩放比例,我们将z
赋值给zoom
。图片同样放大/缩小.但是手势结束时,图片不会还原。
@State var zoom:CGFloat=1
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).scaleEffect(zoom).gesture(MagnificationGesture().onEnded({z in zoom=z}))
这段代码,我们在onEnd
中设置zoom
的数值,图片只有在手势完成之后才显示出来缩放。
以上的三段代码展示了三个回调函数的作用。那么我们要完成一个图片的缩放功能是如何实现的呢。代码如下
@State var zoom:CGFloat=1Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).scaleEffect(zoom).gesture(MagnificationGesture().onChanged({z inzoom += z>1 ? 0.05 : -0.05 }))
- 通过
onChange
控制图片缩放,手势操作结束之后图片依旧保持缩放状态。 - 没有直接将
z
赋值给zoom
,而是判断z
是放大还是缩小,>1时zoom
增加,图片放大,<1时zoom
减小,图片缩小。这样做的原因是为了保持图片的连续放大或者缩小。如果我们直接赋值给zoom
,假设上次手势是放大了3倍,而这次手势也是放大操作,但只放大了2倍,那么图片就会由放大3倍变成放大2倍,实际变小了,我们期望是图片继续放大的,这样的结果不是我们期望的。所以,我们根据手势的操作来设置放大比例,手势只要是放大操作,那么放大比例就增加,保证图片是放大的。
拖拽
我们设定场景是,通过拖拽让图片在不同的位置显示。捕获的Gesture是DragGesture
.代码如下
@GestureState var dragOffset=CGSize.zeroImage("j1").resizable().frame(width: 200, height: 200, alignment: .leading).offset(x: dragOffset.width, y: dragOffset.height).gesture(DragGesture().updating($dragOffset, body: { gesture,dragoff,transaction indragoff.width=gesture.translation.widthdragoff.height=gesture.translation.height}))
我们先在updating
处理,这个需要绑定的是一个CGSize
类型的属性。通过这个属性的width
和height
来设置图片的偏移位置,在拖拽结束时,图片会到原先的位置。
@State var offsetX:CGFloat=0
@State var offsetY:CGFloat=0
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).offset(x: offsetX, y: offsetY).gesture(DragGesture().onEnded({v inoffsetX=v.translation.widthoffsetY=v.translation.height}))
这段代码是在手势操作结束捕获。图片会移动到手指抬起的位置。手指移动时没有任何变化。
@State var offsetX:CGFloat=0
@State var offsetY:CGFloat=0
let step:CGFloat=3Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).offset(x: offsetX, y: offsetY).gesture(DragGesture().onChanged({gesture inoffsetX+=gesture.translation.width>0 ? step : -stepoffsetY+=gesture.translation.height>0 ? step: -step}))
这段代码,我们用手按住图片进行滑动,图片就随着手移动,实现了图片的拖拽功能。手势结束时图片还是在结束的位置。其中gesture
可以认为是一个手势操作的封装对象,我们获取了这个对象中的位移相关的属性。通过判断位移的位置设定图片偏移量x,y的数值。同样为了让图片保持连续移动,我们没有直接将手势结束时的位置赋值给图片,而是判断出方向再将X
,Y
的偏移量进行增加或者减少。
旋转
通过旋转手势让图片旋转,同样有3个回调函数
@GestureState var gestureAngle:Angle=Angle(degrees: 0)
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).rotationEffect(gestureAngle).gesture(RotationGesture().updating($gestureAngle, body: {angle,ganlge,transaction inganlge=angle}))
手势结束后,图片会还原。
@State var angle:Angle=Angle(degrees: 0)
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).rotationEffect(angle).gesture(RotationGesture().onChanged({ a in angle=a}))
手势结束后,图片保留旋转状态
@State var angle:Angle=Angle(degrees: 0)
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).rotationEffect(angle).gesture(RotationGesture().onEnded({a in angle=a}))
只有在手势结束之后图片才会旋转并保持旋转状态
点击
点击手势只有2个回调函数 updating
和onEnd
,在gesture
时通过count:Int
的构造设定需要连续点击的触发次数。
@GestureState var tap:CGFloat=0
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).rotationEffect(angle).gesture(TapGesture().updating($tap, body: { d,t,trasaction inprint("d \(d)")print("tap \(t)")}))
没有任何反应
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).rotationEffect(angle).gesture(TapGesture(count: 2).onEnded({print("tap over")}))
连续点击2次会打印tap over
长按
长按手势也有三个回调函数
@GestureState var longPress=falseImage("j1").resizable().frame(width: 200, height: 200, alignment: .leading).rotationEffect(angle).gesture(LongPressGesture().updating($longPress, body: {b ,state,transaction inprint("b \(b)")print("state \(state)")}))
手指放上去就会触发,b
就为true。
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).rotationEffect(angle).gesture(LongPressGesture().onChanged({b in print(b)}))
同updating
手指放上去就会触发
Image("j1").resizable().frame(width: 200, height: 200, alignment: .leading).rotationEffect(angle).gesture(LongPressGesture(minimumDuration: 5, maximumDistance: 5).onEnded({b in print(b)}))
onEnd
回调函数能体现长按是否被正确触发,在这段代码中构造函数添加了2个参数minimumDuration
按住的时间maximumDistance
按住时最大的移动距离,按住的时间要大于设定的minimumDuration
并且手指移动的距离要小于maximumDistance
才会真正触发。如果没有满足上面2个条件,不会打印b
。
方式二
SwiftUI对于点击和长按这两个手势提供了几个简单的修饰函数。
点击
对于点击手势有三个函数onTapGesture(perform: <() -> Void)
,onTapGesture{code}
,onTapGesture(count: Int, perform: () -> Void)
都是在点击手势完成时调用,闭包函数时调用时的代码。具体使用方式可以对比方式一的函数。
长按
长按手势的处理有两个函数onLongPressGesture(perform: () -> Void)
,onLongPressGesture(minimumDuration: Double, maximumDistance: CGFloat, perform: () -> Void, onPressingChanged: ((Bool) -> Void)?)
,可以对比方式一的函数写代码。
总结
- 手势捕捉的两种方式。
- 每个手势捕捉之后有3个回调函数
updating(_:body:)
,onChanged(_:)
,onEnd(_:)
。 - 手势操作的变量修饰:
@GestureState
- View的定位函数
offset
- 多个手势可以通过
gesture
多次捕捉。当然还有simultaneousGesture
,highPriorityGesture
处理不同情况。
SwiftUI 手势操作相关推荐
- Swift开发:仿Clear手势操作(拖拽、划动、捏合)UITableView
2019独角兽企业重金招聘Python工程师标准>>> 这是一个完全依靠手势的操作ToDoList的演示,功能上左划删除,右划完成任务,拖拽调整顺序,捏合张开插入. 项目源码: ht ...
- 移动端手势操作--两点同时点击的实现方案
手机屏幕单点接触是click事件,那两点接触呢?最近项目中的需求是监视手机屏幕的两个手指同时点击事件.类似的需求还是多个手指点击等.技术实现方案很简单,但是由于一个人思路有限,结果绕了一些弯路.记录下 ...
- iphonex如何关机_iphonex常用手势操作有哪些 iphonex常用手势操作介绍【详解】
iphonex常用手势操作有什么?相信小伙伴们一定很好奇,下面小编为大家带来了iphonex常用手势操作大全一览,感兴趣的小伙伴赶紧跟着小编一起来看看吧. 如何唤醒Siri 苹果一直追求极简的设计思路 ...
- iOS手势操作简介(五)
利用手势操作实现抽屉效果: 第一步:搭建UI (void)addChildView { // left UIView *leftView = [[UIView alloc] initWithFrame ...
- iOS手势操作简介(一)
iOS中能够响应手势操作的类必须要继承自UIResponder,才能够处理手势响应操作. 默认继承了UIResponder的类有:UIApplication UIViewController UIVi ...
- android touch事件坐标原点,Android onTouch事件与手势操作
触摸,手势操作已经很好的融入了我们的生活.那么Android开发中触摸事件要如何捕捉?如何处理?如何识别手势?事件的传递机制又是怎么样的?下面我们将通过一个小例子来进行这方面的学习. 先看效果图 如上 ...
- 《移动App测试的22条军规》—App测试综合案例分析23.4节测试微信App的手势操作...
本节书摘来自异步社区<移动App测试的22条军规>一书中的App测试综合案例分析,第23.4节测试微信App的手势操作,作者黄勇,更多章节内容可以访问云栖社区"异步社区" ...
- 安卓学习笔记14:安卓手势操作编程
文章目录 零.学习目标 一.安卓手势操作原理 二.安卓手势类与接口 1.MotionEvent 2.GestureDetector 3.OnGestureListener 三.教学案例--利用手势切换 ...
- Android 触摸及手势操作GestureDetector
现在的智能手机不敢说百分百的都是触摸屏,也应该是百分之九九以上为触摸屏了,触摸屏为我们操作无键盘.无鼠标的手机系统带来了很多的便利.当用户触摸屏幕时会产生很多的触摸事件,down.up.move等等. ...
最新文章
- Linux系统(一)文件系统、压缩、打包操作总结
- 大竹中学2021高考成绩查询,四川大竹中学2021录取分数线
- 【Rsyslog】facilty priority
- 【通知】3月第三周直播预告,模型精简前沿技术,人脸分析与编辑,图像风格化...
- Cortex‐M3-存储器保护单元(MPU)
- Activiti第二篇【管理流程定义、执行任务和流程实例、流程变量】
- 用c语言实现串的存储结构是指,数据结构学习笔记-串(C语言实现)
- 一张图搞懂Spring bean的完整生命周期
- “约见”面试官系列之常见面试题之第七十四篇之v-if和v-for优先级(建议收藏)
- python提取部分字符串三参数_python3 字符串属性(三)
- SCPPO(二十六):测算过程中问题的解决总结
- Viliv N5 GPS安装及使用方法
- Mysql中,int(10)和int(11)的区别
- html5给页面添加雨滴特效,JavaScript canvas实现雨滴特效
- 基于89C51单片机的智能小车——06.测速小车
- 协鑫集成的这款组件,真的很适合农光互补!
- 【JZOJ5234】外星人的路径
- sparkStreaming+kafka+redis小项目实战
- 【论文解读】NAACL 2021 对比自监督学习的上下文和一般句子表征:以篇章关系分析为例
- 采购行业权威证书对比