Gesture Recognizers与触摸事件分发[转]
一.Gesture Recognizers
Gesture Recognizers是在iOS3.2引入的,可以用来识别手势、简化定制视图事件处理的对象。Gesture Recognizers的基类为UIGestureRecognizer,这一个抽象基类,定义了实现底层手势识别行为的编程接口。在UIKit框架中提供了6个具体的手势识别类,用来识别常见的手势。这6个手势识别器类为:
- UITapGestureRecognizer:用来识别点击手势,包括单击,双击,甚至三击等。
- UIPinchGestureRecognizer:用来识别手指捏合手势。
- UIPanGestureRecognizer:用来识别拖动手势。
- UISwipeGestureRecognizer:用来识别Swipe手势。
- UIRotationGestureRecognizer:用来识别旋转手势。
- UILongPressGestureRecognizer:用来识别长按手势。
为了识别手势,需要将Gesture Recognizers关联到其检测触摸事件的view上,可以使用UIView的addGestureRecognizer:方法将手势识别器绑定到视图上。Gesture Recognizers在触摸事件处理流程中,处于观察者的角色,其不是view层级结构的一部分,所以也不参与responder chain。在将触摸事件发送给hit-test view之前,系统会先将触摸事件发送到hit-test view上绑定的或hit-test view父视图(superview)上绑定的Gesture Recognizers上。其流程大概如下图所示:
注:图中view与Gesture Recognizer的关系是,Gesture Recognizer关联在view或view的superview(可能多级)上。
二.Gesture Recognizers与事件分发路径的关系
Gesture Recognizers可能会延迟将触摸事件发送到hit-test view上,默认情况下,当Gesture Recognizers识别到手势后,会向hit-test view发送cancel消息,来取消之前发给hit-test view的事件。控制这个流程的是UIGestureRecognizer的三个属性
- cancelsTouchesInView (默认为YES)
- delaysTouchesBegan (默认为NO)
- delaysTouchesEnded (默认为YES)
cancelsTouchesInView为YES,表示当Gesture Recognizers识别到手势后,会向hit-test view发送 touchesCancelled:withEvent:消息来取消hit-test view对此触摸序列的处理,这样只有Gesture Recognizers能响应此触摸序列,hit-test view不再响应。如果为NO,则不发送touchesCancelled:withEvent:消息给hit-test view,这样会使Gesture Recognizers和hit-test view同时响应触摸序列。
delaysTouchesBegan为NO,表示触摸序列开始时,而手势识别器还未识别出此手势时,touch事件会同时发向hit-test view,这样在手势识别器还未识别出此手势,hit-test view同时也可以收到同样的触摸事件。如果为YES,则在手势识别器在识别手势的过程中,不会有任何触摸事件发送给hit-test view,如果手势识别器最终识别到了手势,则也不会发送任何消息(包括touchesCancelled:withEvent:)给hit-test view;若干手势识别最终没有识别到手势,则所有的触摸事件在发给hit-test view处理。关于这个特性,可参考UIScrollView的delaysContentTouches属性。这样属性也谨慎使用,使用不当会导致UI无响应。
delaysTouchesEnded,在文档上的解释是,当手势识别器在识别手势时,对于UITouchPhaseEnded阶段的touch会延迟发送给hit-test view,在手势识别成功后,发送给hit-test view cancel消息,手势识别失败时,发送原来的end消息。其给出了了这样的例子识别双击操作的UITapGestureRecognizer对象,其numberOfTapsRequired设为2,在用户进行双击操作时,如果delaysTouchesEnded为NO,则hit-test view中的调用序列为
touchesBegan:withEvent:,
touchesEnded:withEvent:,
touchesBegan:withEvent:,
and touchesCancelled:withEvent:
如果delaysTouchesEnded为YES,则调用序列为:
touchesBegan:withEvent:,
touchesBegan:withEvent:,
touchesCancelled:withEvent:,
touchesCancelled:withEvent:
但我在实际测试时,并非如此,实际测试的结果是,如果delaysTouchesEnded为NO,则调用序列为:
touchesBegan:withEvent:,
touchesEnded:withEvent:,
TapGestureRecognizer 检测到双击如果delaysTouchesEnded为YES,则调用序列为:
touchesBegan:withEvent:,
touchesEnded:withEvent:,
TapGestureRecognizer 检测到双击
touchesCancelled:withEvent:
这个问题还没搞清楚!三.多个Gesture Recognizer之间的关系
在一个view上可以绑定多个Gesture Recognizer,在默认情况下,触摸序列中的触摸事件会以不确定的次序在各个gesture recognizer中传递,直到事件最终发送给hit-test view(如果中间没被Gesture Recognizer识别出并截获的话)。多个Gesture Recognizer之间的关系也可以根据需要定制,主要有下面几种行为
1.使其中一个gesture recognizer失败的情况下,另一个gesture recognizer才能分析事件。
以同时识别单击操作和双击操作为例,两个gesture recognizers分别用来识别单击和双击,分别为singleTapGesture和doubleTapGesture。在默认情况下,当用户进行单击操作时,singleTapGesture会识别出一个单击操作,doubleTapGesture也会识别出一个双击动作,但我们的意图是,这仅仅是一个双击操作。在这种情况下我们可以使用UIGestureRecognizer的requireGestureRecognizerToFail:方法来使singleTapGesture在doubleTapGesture识别识别的时候才分析事件,如果doubleTapGesture识别出双击事件,则singleTapGesture不会有任何动作。
[singleTapGesture requireGestureRecognizerToFail:doubleTapGesture];
需要注意的是,在这种情况下,如果用户进行单击操作,需要一段延时(即doubleTapGesture识别失败),singleTapGesture才会识别出单击动作,进行单击处理,这段时间很多,对实际使用几乎没有影响。
2.精确控制gesture recognizer是否响应某个事件或事件序列.
在UIGestureRecognizerDelegate协议中有两个可选方法可以控制gesture recognizer是否需要识别某些事件
- gestureRecognizerShouldBegin:
此方法在gesture recognizer视图转出UIGestureRecognizerStatePossible状态时调用,如果返回NO,则转换到UIGestureRecognizerStateFailed;如果返回YES,则继续识别触摸序列.(默认情况下为YES) - gestureRecognizer:shouldReceiveTouch:
此方法在window对象在有触摸事件发生时,调用gesture recognizer的touchesBegan:withEvent:方法之前调用,如果返回NO,则gesture recognizer不会看到此触摸事件。(默认情况下为YES).
另外,在UIGestureRecognizer类中也有两个可以重写的方法来完成与Delegate方法中相同的功能
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer;
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer;3.允许多个手势识别器共同识别
默认情况下,两个gesture recognizers不会同时识别它们的手势,但是你可以实现UIGestureRecognizerDelegate协议中的
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:方法对其进行控制。这个方法在这两个gesture recognizers中的任意一个将block另一个的触摸事件时调用,如果返回YES,则两个gesture recognizers可同时识别,如果返回NO,则并不保证两个gesture recognizers必不能同时识别,因为另外一个gesture recognizer的此方法可能返回YES。也就是说两个gesture recognizers的delegate方法只要任意一个返回YES,则这两个就可以同时识别;只有两个都返回NO的时候,才是互斥的。默认情况下是返回NO。有这样一个例子,如果要侦测在window上的所有触摸事件,可以将gesture recognizer关联到window上,默认情况下如果手势被window识别,则子视图中的gesture recognizer就失效了,而我们在window上的gesture recognizer的目的只是监控所有事件,但并不处理这些事件,具体事件的处理还需要子视图中的各个gesture recognizer去处理,这样我们可以实现window上绑定gesture recognizer的delegate方法,使gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:返回YES即可。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
四.UIScrollView的类似行为
scroll view没有滚动栏,当在scroll view上有触摸行为时其要识别出触摸行为的目的是scroll view本身还是其内容子视图。定制scrollview如何处理这种情况,看查看UIScrollView类的下列属性和方法。
– touchesShouldBegin:withEvent:inContentView:
– touchesShouldCancelInContentView:
canCancelContentTouches
delaysContentTouches参考:
Event Handling Guide for iOS – Gesture Recognizers
UIGestureRecognizer Class Reference
UIGestureRecognizerDelegate Protocol Reference
Detecting all touches in an app
UIScrollView Class Reference
How to recognize swipe gesture in UIScrollView
UIGestureRecognizer blocks subview for handling touch events
UIButton touch is delayed when in UIScrollView
Why is scrolling a UITableView much more responsive than scrolling a UIScrollView?
How to cancel touches exactly like UIScrollView?
Gesture Recognizers与触摸事件分发[转]的更多相关文章
- cocos2dx 中触摸事件分发一些解读
触摸事件分发中几个代码解读: 怎么说呢,感觉cocos2dx中的消息分发机制,相对于android中触摸事件分发机制要简单的多.因为android中要做区域判断,过滤器,以及父子组件分发给谁等等的逻辑 ...
- android自定义控件(9)-Android触摸事件分发机制
触摸事件的传递机制: 首先是最外层的viewgroup接收到事件,然后调用会调用自己的dispatchTouchEvent方法.如果在ACTION_DOWN的时候dispatchTouchEven ...
- IOS 触摸事件分发机制详解
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:MelonTeam 前言 很多时候大家都不关心IOS触摸事件的分发机制的实现原理,当遇到以下几种情形的时候你很可能抓破头皮都找不到解决方案 ...
- 图解Android触摸事件分发
Android中触摸事件传递过程中最重要的是dispatchTouchEvent().onInterceptTouchEvent()和onTouchEvent()方法. View和Activity有d ...
- 高级UI晋升之触摸事件分发机制(一)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 0. 前言 鉴于安卓分发机制较为复杂,故分为多个层次进行讲解,分别为基础篇.实践 ...
- iOS 触摸事件与手势识别器(Gesture Recognizers)
Gesture Recognizers与触摸事件分发 通过一个问题引出今天的知识: 1.大家应该都遇见过 当需要给tableView 添加一个tap 手势识别 但是tableView 的上的事件(滑动 ...
- 一个demo让你彻底理解Android中触摸事件的分发
注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOW ...
- cocos2d-x游戏引擎核心之五——触摸事件和触摸分发器机制
一.触摸事件 为了处理屏幕触摸事件,Cocos2d-x 提供了非常方便.灵活的支持.在深入研究 Cocos2d-x 的触摸事件分发机制之前,我们利用 CCLayer 已经封装好的触摸接口来实现对简单的 ...
- Cocos2d-x 学习笔记(16) 触摸事件与分发 EventTouch dispatchTouchEvent EventListenerTouch
1. EventTouch 触摸事件的成员变量:枚举EventCode.存储Touch的容器. 不同的EventCode代表不同时机的触摸事件,能让监听器调用不同的回调函数. enum class E ...
随机推荐
- git 版本控制
用gitbash进入类似命令行的窗口 用命令 cd e:/learngit 进入该目录,然后在此目录下初始化$ git init, 于是该文件夹就成为了一个工作区,里面的.git文件就是版本库(rep ...
- xxxxxxx
int c; int b; bool h;
- Ajax在html页面获取后台XML文件资源
一.准备工具 站长吧ASP调试工具.exe,这个工具是为了快速建立asp环境,方便调试. 二.建立文件夹 1.建立网站根文件夹,名字随意,将站长吧ASP调试工具.exe复制到根文件夹: 2.建立xml ...
- requestAnimationFrame
(function() { var lastTime = 0; var vendors = ['webkit', 'moz']; for(var x = 0; x < vendors.lengt ...
- QT QString 很全的使用 (转)
QString, QByteArray, 和 QVariant这三个类和容器有许多相同之处,并且在一些情况下可以被当作特殊的容器. 同样,像容器,这些类使用隐式共享来优化内存和速度. 我们将从QStr ...
- SqlServer阅读收集
1.根据字段名,查找相关表--INFORMATION_SCHEMA.COLUMNS SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME ...
- 命令模式(Command Pattern)
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开.命令模式是为了解决命令的请求者和命令的实现者之间的耦合关系. 将来自客户端的请求传入一个对象,从而使你可用不同的请求对客户进行参 ...
- 一般处理程序上传文件(html表单上传、aspx页面上传)
html 表单上传文件 一般处理程序由于没有 apsx 页面的整个模型和控件的创建周期,而比较有效率.这里写一个用 html 表单进行文件上传的示例. 1. 表单元素选用 ...
- sql查询语句
//查询表的字段名和字段类型select column_name,data_type from information_schema.columns where table_name = '表名' / ...
- Mysql-cluster7.5
Data nodes: shell> rpm -Uhv mysql-cluster-community-data-node-7.5.5-1.1.el7.x86_64.rpm SQL nodes: ...