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——触摸事件 视图检测和事件传递的更多相关文章

  1. IOS 触摸事件分发机制详解

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:MelonTeam 前言 很多时候大家都不关心IOS触摸事件的分发机制的实现原理,当遇到以下几种情形的时候你很可能抓破头皮都找不到解决方案 ...

  2. 【原】iOS触摸事件深度解析

    概述 本文主要解析从我们的手指触摸苹果设备到最终响应事件的整个处理机制.本质上讲,整个过程可以分为两个步骤: 步骤1:找目标.在iOS视图层次结构中找到触摸事件的最终接受者: 步骤2:事件响应.基于i ...

  3. 浅谈iOS触摸事件理解

    iOS的触摸事件个人总结,分为两步: 第一步:是找到哪个视图上触摸 第二步:分析由谁去响应(响应者连) 1.寻找被触摸的视图原理如下图 hitText:withEvent:的方法处理流程: 首先会在当 ...

  4. iOS触摸事件深度解析-备用

    概述 本文主要解析从我们的手指触摸苹果设备到最终响应事件的整个处理机制.本质上讲,整个过程可以分为两个步骤: 步骤1:找目标.在iOS视图层次结构中找到触摸事件的最终接受者: 步骤2:事件响应.基于i ...

  5. iOS触摸事件深入

    转载自:http://www.cnblogs.com/wengzilin/p/4720550.html 概述 本文主要解析从我们的手指触摸苹果设备到最终响应事件的整个处理机制.本质上讲,整个过程可以分 ...

  6. iOS 中事件的响应链和传递链

    iOS事件链有两条:事件的响应链:Hit-Testing事件的传递链 响应链:由离用户最近的view向系统传递.initial view –> super view –> ….. –> ...

  7. iOS 触摸事件与UIResponder(内容根据iOS编程编写)

    触摸事件 因为 UIView 是 UIResponder 的子类,所以覆盖以下四个方法就可以处理四种不同的触摸事件: 1.  一根手指或多根手指触摸屏幕 - (void)touchesBegan:(N ...

  8. IOS触摸事件和手势识别

    IOS触摸事件和手势识别 目录 概述 触摸事件 手势识别 概述 为了实现一些新的需求,我们常常需要给IOS添加触摸事件和手势识别 触摸事件 触摸事件的四种方法 -(void)touchesBegan: ...

  9. iOS:触摸控件UITouch、事件类UIEvent

    UITouch:触摸控件类   UIEvent:事件类 ❤️❤️❤️UITouch的介绍❤️❤️❤️ 一.触摸状态类型枚举 typedef NS_ENUM(NSInteger, UITouchPhas ...

随机推荐

  1. Java调度框架Quartz简单示例

    Quartz的大名如雷贯耳,这里就不赘述,而且本文也不作为深入探讨,只是看完Quartz的官方文档后,下个简单示例,至少证明曾经花了点时间学习过,以备不时之需. Quartz使用了SLF4J,所以至少 ...

  2. hudson入门

    持续集成hudson入门博客分类: Java 单元测试配置管理maven项目管理Tomcat         极限编程中一项建议实践便是持续集成,持续集成是指在开发阶段,对项目进行持续性自动化编译.测 ...

  3. 每天一个Linux命令 1

    nl命令在Linux系统中用来计算文件中行号.nl可以将输出的文件内容自动的加上行号!其默认的结果与cat -n有点不太一样,nl可以将行号做比较多的显示设计,包括位数与是否自动补齐0等等的功能. 1 ...

  4. 求取水仙花数 && 将整数分解成质因数

    [程序3] 题目:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身.例如: 153是一个"水仙花数", ...

  5. PHP数据访问基础知识(20161028)

    数据访问 动态页面的特征:能够读取数据库,网页的内容都是从数据库读出来的,而不是写死的 所有的程序归根结底都是对数据的增删改查 如何用服务器的PHP来操作服务器的MySQL,Apache则是用来管理, ...

  6. Python中参数是传值,还是传引用?

    在 C/C++ 中,传值和传引用是函数参数传递的两种方式,在Python中参数是如何传递的?回答这个问题前,不如先来看两段代码. 代码段1: def foo(arg): arg = 2 print(a ...

  7. c# 将匿名类或者集合转Json格式数据一些方法

    要说写这个功能呢也是因为工作需要,白天呢上班写个Web页面需要ajax请求后台并将数据以Json格式传会前端,由于公司特殊性吧,不能连外网(很苦比).所以只有等到晚上回家上网边查边写! public ...

  8. javascript-基本数据类型和转换

    ECMAScript中有5种基本数据类型:Undefined.Null.Boolean.Number.String.还有1种复杂数据类型-Object,Object实质上是由一组无序的名值对(键值对) ...

  9. Postman使用教程——调试网络接口的凶器

    postman是谷歌浏览器的一个插件,干什么用的呢?跟题目一样,就是用来调试网络接口的.在我们程序猿做程序的时候,如果做网络应用的开发,比如一些B/S.C/S,我们总会给别人一些网络接口,也会使用别人 ...

  10. 分享小知识:善用Group By排序

    以下列举了公用表/临时表/聚合函数三个因素为例子(覆盖索引因素除外,有利用此类索引都会以索引顺序)  环境: Microsoft SQL Server 2014 (SP1-GDR) (KB319472 ...