基本概念

在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修饰,onChangez是缩放比例,我们将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 }))
  1. 通过onChange控制图片缩放,手势操作结束之后图片依旧保持缩放状态。
  2. 没有直接将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类型的属性。通过这个属性的widthheight来设置图片的偏移位置,在拖拽结束时,图片会到原先的位置。

@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个回调函数 updatingonEnd,在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)?),可以对比方式一的函数写代码。

总结

  1. 手势捕捉的两种方式。
  2. 每个手势捕捉之后有3个回调函数updating(_:body:),onChanged(_:),onEnd(_:)
  3. 手势操作的变量修饰:@GestureState
  4. View的定位函数offset
  5. 多个手势可以通过gesture多次捕捉。当然还有simultaneousGesturehighPriorityGesture处理不同情况。

SwiftUI 手势操作相关推荐

  1. Swift开发:仿Clear手势操作(拖拽、划动、捏合)UITableView

    2019独角兽企业重金招聘Python工程师标准>>> 这是一个完全依靠手势的操作ToDoList的演示,功能上左划删除,右划完成任务,拖拽调整顺序,捏合张开插入. 项目源码: ht ...

  2. 移动端手势操作--两点同时点击的实现方案

    手机屏幕单点接触是click事件,那两点接触呢?最近项目中的需求是监视手机屏幕的两个手指同时点击事件.类似的需求还是多个手指点击等.技术实现方案很简单,但是由于一个人思路有限,结果绕了一些弯路.记录下 ...

  3. iphonex如何关机_iphonex常用手势操作有哪些 iphonex常用手势操作介绍【详解】

    iphonex常用手势操作有什么?相信小伙伴们一定很好奇,下面小编为大家带来了iphonex常用手势操作大全一览,感兴趣的小伙伴赶紧跟着小编一起来看看吧. 如何唤醒Siri 苹果一直追求极简的设计思路 ...

  4. iOS手势操作简介(五)

    利用手势操作实现抽屉效果: 第一步:搭建UI (void)addChildView { // left UIView *leftView = [[UIView alloc] initWithFrame ...

  5. iOS手势操作简介(一)

    iOS中能够响应手势操作的类必须要继承自UIResponder,才能够处理手势响应操作. 默认继承了UIResponder的类有:UIApplication UIViewController UIVi ...

  6. android touch事件坐标原点,Android onTouch事件与手势操作

    触摸,手势操作已经很好的融入了我们的生活.那么Android开发中触摸事件要如何捕捉?如何处理?如何识别手势?事件的传递机制又是怎么样的?下面我们将通过一个小例子来进行这方面的学习. 先看效果图 如上 ...

  7. 《移动App测试的22条军规》—App测试综合案例分析23.4节测试微信App的手势操作...

    本节书摘来自异步社区<移动App测试的22条军规>一书中的App测试综合案例分析,第23.4节测试微信App的手势操作,作者黄勇,更多章节内容可以访问云栖社区"异步社区" ...

  8. 安卓学习笔记14:安卓手势操作编程

    文章目录 零.学习目标 一.安卓手势操作原理 二.安卓手势类与接口 1.MotionEvent 2.GestureDetector 3.OnGestureListener 三.教学案例--利用手势切换 ...

  9. Android 触摸及手势操作GestureDetector

    现在的智能手机不敢说百分百的都是触摸屏,也应该是百分之九九以上为触摸屏了,触摸屏为我们操作无键盘.无鼠标的手机系统带来了很多的便利.当用户触摸屏幕时会产生很多的触摸事件,down.up.move等等. ...

最新文章

  1. Linux系统(一)文件系统、压缩、打包操作总结
  2. 大竹中学2021高考成绩查询,四川大竹中学2021录取分数线
  3. 【Rsyslog】facilty priority
  4. 【通知】3月第三周直播预告,模型精简前沿技术,人脸分析与编辑,图像风格化...
  5. Cortex‐M3-存储器保护单元(MPU)
  6. Activiti第二篇【管理流程定义、执行任务和流程实例、流程变量】
  7. 用c语言实现串的存储结构是指,数据结构学习笔记-串(C语言实现)
  8. 一张图搞懂Spring bean的完整生命周期
  9. “约见”面试官系列之常见面试题之第七十四篇之v-if和v-for优先级(建议收藏)
  10. python提取部分字符串三参数_python3 字符串属性(三)
  11. SCPPO(二十六):测算过程中问题的解决总结
  12. Viliv N5 GPS安装及使用方法
  13. Mysql中,int(10)和int(11)的区别
  14. html5给页面添加雨滴特效,JavaScript canvas实现雨滴特效
  15. 基于89C51单片机的智能小车——06.测速小车
  16. 协鑫集成的这款组件,真的很适合农光互补!
  17. 【JZOJ5234】外星人的路径
  18. sparkStreaming+kafka+redis小项目实战
  19. 【论文解读】NAACL 2021 对比自监督学习的上下文和一般句子表征:以篇章关系分析为例
  20. 采购行业权威证书对比

热门文章

  1. 过滤器,监听器,拦截器的区别
  2. 练习8 利用有限状态机进行时序逻辑设计
  3. Android不刷机下的app2sd方法(dex cache占空间解决篇)
  4. SRAM和DRAM存储原理
  5. 树莓派(一) 控制LED灯和声音传感器(python)
  6. 日常英语单词 - 足球
  7. Head First JAVA 拾忆-1
  8. 神思通用100型读身份证
  9. 男人的累,男人的泪…………
  10. 2021年安全类比赛writeup总结