IOS——触摸事件 视图检测和事件传递
iPhone上有非常流畅的用户触摸交互体验,能检测各种手势:点击,滑动,放大缩小,旋转。大多数情况都是用UI*GestureRecognizer这样的手势对象来关联手势事件和手势处理函数。也有时候,会看到第三方代码里会在如下函数中进行处理:
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
那么问题就来了,手势和touch到底有什么区别和联系?这一切还得从头iOS触摸事件检测,以及UIResponder(响应者)开始说起。
以下是我的总结,我建议大家先看完官方说明,自己先琢磨过,有了自己的体会,再来看我的总体。我的总结起来就2点:
第一步,当我们触摸了屏幕,iOS是如何找到我们触摸哪个视图。
第二步,当确定了触摸的视图,又如何传递和处理触摸事件。
第一步 寻找发生触摸的视图
检测的目的是为了找到触摸是发生在哪个视图上(UIView)。这个检测的顺序是从底向上的检测过程。首先UIApplication会传递给UIWindow,然后再由UIWindow传递给顶级的视图,顶级视图会进一步遍历其所有的subviews。UIView有个函数叫hitTest,如果触摸事件是发生在该视图中,则该函数会返回非空UIView;然后该视图递归其subviews,最后发现最终的subview。
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
-这是一个从底向上的过程:从UIApplication->UIWindow
->顶级视图->下级视图;
-这是一个遍历和递归的过程:遍历所有的subview,递归调用subview的subview。
-这是一个寻找确定hit-test视图的过程:我们把最终找到的视图成作为:hit-test view。
这里有个特殊情况,如果一个视图被设置为user-interaction = NO,那么hitTest会返回空指针。某些继承自uiview的组件默认user-interaction = NO,比方说UIImageView。
再考虑一个情况,如果有个视图盖在另一个视图之上,触摸发生在了它们的交界区域,最终检测结果会是什么?经过测试,发现顶层视图响应了触摸事件。这个事可以这么来解释,虽然它们同属于一个uiview的子视图,当父视图循环其子视图,一定会先从最上层的子视图开始。所以,被覆盖的视图没有机会被调用hitTest。
第二步 传递和处理触摸事件:UIResponder(响应者)
从UIResponder的头文件来看,它不仅能处理触摸事件,还能处理手机移动事件(比方晃动手机),并处理远程事件。这里我们只看触摸事件:
–touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:
UIView继承自UIResponder;UIWindow继承自UIView,因此它也是UIResponder的子类。
第一步结束一定能找到hit-test view,然后就开始调用其UIResponder->touchse*函数进行处理;
如果我们不重写touches函数的话,默认会调用self->nextResponder->touches*进一步把点击
事件传递下去。每个responder都有个nextRepsonder,这就形成了一个响应者连。值得注意的是:
1.如果我们重写touches*函数时,不调用[super touches*]的话,那么事件就不会继续传递下去。
2.UIViewController也继承自UIPesponder,所以响应链中除了有视图,也会有试图控制器,所以
视图控制区中,也可以实现touches*函数。
3.关于响应链的形成:看起来响应链是个非常错综复杂的数据链,其实它很简单。每个Responder
只关心其nextResponder就可以了。而关于nextResponder的赋值过程我推测是这样的;
当UIViewController初始化时,将其关联的视图的nextResopnder设为自己;当一个子视图add时
就自动将其nextResponder设为其父视图。
UI*GestureRecongnizer,UIVontrol和touches的关系
UITouch是底层的触摸操作,如果开发人员要将其解释为各种手势操作,那需要太多工作量。而有了
UI*GestureRecognizer的帮助,我们就不需要关心touches*函数了。UIControl是同样的道理,它帮
助我们脱离太过底层的触摸操作,我们直接解释为按钮按下,抬起等等动作。而且,可见UIControl不会将
触摸事件进一步往下传递。
使用UITouch/UIResponder实现一些黑魔法
1.找到UIView所属的试图控制器
@implementation UIView(ParentController)
-(UIViewController*)ParentController{
UIResponder*responder=[self nextResponder];
while(responder){
if([responder isKindOfClass:[UIViewController class]]){
return (UIViewController*)responder;
}
responder=[responder nextResponder];
}
return nil;
}
@end
2.操作响应触摸事件的视图
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event{
if(!CGRectContainsPoint(self.pageScrollView.frame,point)){
return self.pageScrollView;
}
return [super hitTest:pointwithEvent:event];
}
3.操作响应链
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{
if(!self.dragging){
[self.nextRespondertoucheswithEvent:event];
}
else{
[super touchesBegan:toucheswithEvent:event];
}
}
重要事情再说一次:
1.寻找发生触摸的视图
2.传递处理触摸事件:UIResponder(响应者)
IOS——触摸事件 视图检测和事件传递的更多相关文章
- IOS 触摸事件分发机制详解
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:MelonTeam 前言 很多时候大家都不关心IOS触摸事件的分发机制的实现原理,当遇到以下几种情形的时候你很可能抓破头皮都找不到解决方案 ...
- 【原】iOS触摸事件深度解析
概述 本文主要解析从我们的手指触摸苹果设备到最终响应事件的整个处理机制.本质上讲,整个过程可以分为两个步骤: 步骤1:找目标.在iOS视图层次结构中找到触摸事件的最终接受者: 步骤2:事件响应.基于i ...
- 浅谈iOS触摸事件理解
iOS的触摸事件个人总结,分为两步: 第一步:是找到哪个视图上触摸 第二步:分析由谁去响应(响应者连) 1.寻找被触摸的视图原理如下图 hitText:withEvent:的方法处理流程: 首先会在当 ...
- iOS触摸事件深度解析-备用
概述 本文主要解析从我们的手指触摸苹果设备到最终响应事件的整个处理机制.本质上讲,整个过程可以分为两个步骤: 步骤1:找目标.在iOS视图层次结构中找到触摸事件的最终接受者: 步骤2:事件响应.基于i ...
- iOS触摸事件深入
转载自:http://www.cnblogs.com/wengzilin/p/4720550.html 概述 本文主要解析从我们的手指触摸苹果设备到最终响应事件的整个处理机制.本质上讲,整个过程可以分 ...
- iOS 中事件的响应链和传递链
iOS事件链有两条:事件的响应链:Hit-Testing事件的传递链 响应链:由离用户最近的view向系统传递.initial view –> super view –> ….. –> ...
- iOS 触摸事件与UIResponder(内容根据iOS编程编写)
触摸事件 因为 UIView 是 UIResponder 的子类,所以覆盖以下四个方法就可以处理四种不同的触摸事件: 1. 一根手指或多根手指触摸屏幕 - (void)touchesBegan:(N ...
- IOS触摸事件和手势识别
IOS触摸事件和手势识别 目录 概述 触摸事件 手势识别 概述 为了实现一些新的需求,我们常常需要给IOS添加触摸事件和手势识别 触摸事件 触摸事件的四种方法 -(void)touchesBegan: ...
- iOS:触摸控件UITouch、事件类UIEvent
UITouch:触摸控件类 UIEvent:事件类 ❤️❤️❤️UITouch的介绍❤️❤️❤️ 一.触摸状态类型枚举 typedef NS_ENUM(NSInteger, UITouchPhas ...
随机推荐
- Java IO之File和IO
本系列我们主要总结一下Java中的IO.NIO以及NIO2. java.io.File 学习Java IO,首先让我们来了解File类吧,它是文件和目录路径名的抽象表示形式.因此你千万别误会File类 ...
- 服务器数据库搭建流程(CentOs+mysql)
前言: 服务器上数据库搭建需要知道Linux系统的版本,以前的Ubuntu14.04直接在终端下输入apt-get install (package)便可方便的下载并安装mysql,但是在centOs ...
- Oracle Developer Data Modeler项目实践 (转)
http://www.Oracle.com/webfolder/technetwork/tutorials/obe/db/sqldevdm/r30/datamodel2moddm/datamodel2 ...
- Spring总结_02_Spring概述
一.概念准备 1.应用程序:是能完成我们所需要功能的成品,比如购物网站.OA系统. 2.框架:是能完成一定功能的半成品,比如我们可以使用框架进行购物网站开发:框架做一部分功能,我们自己做一部分功能,这 ...
- 你可记得曾经的-------- C#面向对象的“基础”
1.C#中构造函数定义的理解: ①构造函数名与所在的类名相同 ②构造函数可以重载 ③构造函数可以带参数 ④构造函数没有返回值,且不允许写出void,可以有参也可以无参 ...
- 基于Spring Cloud和Netflix OSS构建微服务,Part 2
在上一篇文章中,我们已使用Spring Cloud和Netflix OSS中的核心组件,如Eureka.Ribbon和Zuul,部分实现了操作模型(operations model),允许单独部署的微 ...
- Json 与GeoJson
1.JSON介绍 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.简单地说,JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然后 ...
- sass 学习
本来看了阮一峰和于江水两位老师的博客,有看了ionic自带的sass文件,原以为自己已经是很熟悉,精通了.可是我居然连ruby都不知道真实惭愧啊,辛亏看了www.sass.hk 我想这篇官方文档肯定 ...
- NoSQL注入的分析和缓解
本文要点介绍: 1.了解针对NoSQL的新的安全漏洞 2.五类NoSQL攻击手段,比如重言式.联合查询.JavaScript 注入.背负式查询(Piggybacked queries),以及跨域违规 ...
- ThreadLocal本地线程变量的理解
一般的Web应用划分为展现层.服务层和持久层三个层次,在不同的层中编写对应的逻辑,下层通过接口向上层开放功能调用.在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程. ...