iOS手势识别详解

一.UIEvent,UITouch在触摸处理中的作用

在iOS系统中,当用户手指开始接触屏幕到所有手指都离开屏幕,这整个过程叫做一个multitouch sequence.这个过程可能有多点触碰。

而在这整个过程中,系统需要一个对象来存储相关的信息,这个对象就是UIEvent。一旦一个新的触摸过程开始,一个新的UIEvent对象就被建立,并且随着触摸状态的改变不断更新自己的信息,一个完整的触摸过程对应一个UIEvent的实例

那UITouch又是什么呢?前面提到过,在一次触摸过程中,可能有多个手指在触摸,即所谓的多点触控,而一个UITouch的实例则对应一个手指的触摸过程,当UITouch的实例所对应的手指的触摸状态发生改变时,UITouch的状态就会被更新。因为一个触摸过程可能是多点触碰的,因此一个UIEvent实例会有多个UITouch

open var allTouches: Set<UITouch>? { get }

总结:

  • 从手指开始触摸到离开屏幕的整个过程叫做一次multitouch sequence
  • 一次multitouch sequence对应一个UIEvent对象。
  • 一个手指的触摸过程对应一个UITouch对象
  • 一个UIEvent的对象可能含有多个UITouch对象(多点触控

二.在view中利用UITouch进行触摸处理

那么iOS是如何对触摸进行相应的呢?
首先先简单介绍一下UITouch的四种状态(UITouchPhase)

public enum UITouchPhase : Int {

    
    case began // finger开始接触

    case moved // finger正在移动

    case stationary // finger处于静止状态

    case ended // finger离开

    case cancelled // 触摸并没有结束但有其他状况发生导致触摸取消(比如按下了home键)
}

在iOS中,对于触摸的处理是通过UIResponder这个类来实现的,这是一个抽象类,UIView继承自这个类,因此实际上我们所有的触摸事件的处理是通过view来进行的。view是处理触摸的基本单位

因此,实际上每个UITouch实例都有一个view属性,代表持有它的view。view通过以下四个方法来处理触摸事件:

    //当一个touch开始时调用此方法)
    open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
    //当一个touch移动时调用次方法
    open func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?)
    //当一次touch结束时调用此方法
    open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?)
    //当一个touch取消时调用此方法
    open func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?)

在上面四个方法的参数中:

  • touches表示这个view中的所有touch(可能有多个手指在触摸一个view)
  • event代表整个的触摸过程(除了这个view,可能其他的view中也有touches发生,event代表了整个触摸事件)

因此,你可以在view中实现这四个方法,从而就可以达到处理触摸的效果。例如,你如果想要识别用户的长按手势,你只需要在touchBegan这个方法中记录下touch开始的时间,然后在touchMoved方法中记录与开始时间的间隔,如果这个时间间隔大于某个值,你即可以认为这是一次长按过程,然后进行相应的处理。

总结:

  • UITouch有begin,moved等5种状态
  • UIVIew是处理touch的基本单位
  • 系统通过向UIVIew发送touchesBegin的消息来通知触摸状态的改变
  • 可以在UIView中实现touchesBegin等四个方法来实现自定义的处理

三.UIGestureRecognizer的由来及其与UITouch和UIEvent之间的关系

以上谈论的都是iOS比较底层的处理过程,在实际开发中,我们可能根本不会接触到这个东西的,我们都知道,我们实际上是利用来UIGestureRecognizer处理用户的的触摸事件的,那么,UIGestureRecognizer和以上谈论的UITouch和UIEvent以及UIResponder之间有什么关系呢?

为什么会有UIGestureRecognizer

通过上一节的讨论我们知道,如果我们想要识别用户的长按手势,这意味的我们需要定义一个新类继承UIView,然后在这个新类中实现touchesBegen等方法来进行手势识别,然后再来进行相应的处理,这个过程实际上是非常繁琐的,有没有一种便捷的方法呢?

为此,iOS引入了UIGestureRecognizer,将一些常用的手势封装好,(例如UITapGestureRecognizer),然后我们就可以在更高的层面上来进行处理了。

UIGestureRecognizer的工作原理

我们通常在使用UIGestureRecognizer的时候,通常是将它直接加到一个view上去,例如这样:

let tap = UITapGestureRecognizer(target: self, action: "handleTap:")
self.view.addGestureRecognizer(tap)

实际上UIGestureRecognizer的工作原理很简单,它和UIView一样,也实现了touchesBegin等四个方法,借此实现了自己的手势识别过程,当它识别成功时,就通知其target进行相应的处理。一个GestureRecognizer的地位实际上和view的地位是对等的,有UITouch和UIEvent有相同的处理方式

touch的传递过程

  • 当一次touch开始时,会同时传递给(理解这点很重要)相应的view以及view上的GestureRecognizer(如果有的话)
  • 如果一个GestureRecognizer识别到了它的Gesture的话,那么
    • touchesCancelled:forEvent:会发送给相应的view,touch不再传递给这个view
    • 如果这个view上还有其他手势的话,这些手势会forced to fail.(这个是为了保证一次只能有一个手势,避免手势冲突)
  • 如果 a gesture recognizer 识别失败,那么touches不再传递给它,但还是会传递给相应的view
  • 如果view没有实现相应的touches方法的话,那么该事件会沿着响应者链继续传递给下一个相应者处理(比如subview没有实现相应的touches方法,则会调用superview相应的touches方法)

总结:

  • GestureRecognizer和view一样,实现了touchesBegin等四个方法,由此实现了手势识别的过程
  • 当touch开始的时候,是会同时传递给view和view上的GestureRecognizer的,它们会同时调用自己touches方法进行处理
  • 当GestureRecognizer识别成功时,touch便不再传递给view,同时view上的其他GestureRecognizers也会forced to fail
  • 如果 a gesture recognizer 识别失败,那么touches不再传递给它,但还是会传递给相应的view
  • 如果view没有实现touches方法,则该事件会沿着响应者链进行传递
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容