iOS的三种事件:触摸事件/运动事件/远程控制事件

typedef enum {
UIEventTypeTouches,
UIEventTypeMotion,
UIEventTypeRemoteControl,
} UIEventType;

仅仅有继承UIResponder类的对象才干处理事件,如UIView、UIViewController、UIApplication都继承自UIResponder,都能接收并处理事件。UIResponder中定义了上面三类事件相关的处理方法:

以下主要讨论触摸事件。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

事件分发:Hit-Testing View

当用户触摸了设备的屏幕,iOS会识别这一系列触摸事件而且封装到UIEvent对象里面。而且放到application的事件队列,在处理事件时,UIApplication会从事件队列取出最前面的事件并分发处理,一般他会发送给主窗体。接下来主窗体将该事件传递到an initial object来处理,对于触摸事件来说该对象是Touch events

首先会将该事件发送给最合适的对象来处理。对于触摸事件该对象指的是hit-test view,对于其它事件,该对象指的是第一响应者。

UIKit first sends the event to the object that is best suited to handle the event. For touch events, that object is the hit-test view, and for other events, that object is the first responder.

Hit-Testing 指的是找到当前触摸事件在哪个View上发生的过程:假设触摸在一个View的边界里面。就会递归的检查它的子View是不是包括了触摸点。最外面的包括了该触摸点的View就称为hit-test view。

iOS确定了hit-test view后就会将触摸事件传递给该View来处理。

hitTest:withEvent:详细的实现:

hitTest:withEvent:方法首先会调用pointInside:withEvent:方法,假设触摸点在View的内部。该方法返回YES。接下来会递归的调用全部pointInside:withEvent:方法返回YES的子view的hitTest:withEvent:方法。

假设触摸点不在View里面,调用pointInside:withEvent:方法会返回NO。hitTest:withEvent:会返回nil。假设子view在调用pointInside:withEvent:时返回NO,那么以这个子view为父视图的全部子view都不必再检查。也就是说假设触摸点没在一个子view上。那肯定也不可能在该子view的子view上面。也就是说在父view外面的不论什么子view的部分永远不可能接收到触摸事件。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

当触摸最上面绿色控件的红色框框的那部分永远无法接收到触摸事件。

这样的情况在view的clipsToBounds属性设置为NO时会出现。

以下的样例展示了hitTest:withEvent:函数的过程

如果用户触摸了图中的view E。iOS通过例如以下顺序查找hit-test view

1.触摸点在A里面,因此检測子view B和C

2.触摸点不在B里面。可是在C里面。因此检測C的子View D和E。

3.触摸点不在D里面,可是在E里面。而且E是在最外层的包括触摸点的view。因此E就是要找的hit-test view

hitTest:withEvent:函数的实现代码:

1.是否能自己处理?不能。return nil;

2.点在不在当前控件上?没在,return nil。

3.说明能处理触摸事件,而且在当前控件上,是合适的控件。但不一定是最合适的。从后往前遍历自己的子控件,是否是最合适的控件(包括该触摸点的View)。假设是,返回该View。

4.说明没找到比自己合适的View,返回自己。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event的实现:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (self.hidden || !self.userInteractionEnabled || self.alpha < 0.01)
{
return nil;
}
if (![self pointInside:point withEvent:event])
{
return nil;
}
__block UIView *hitView = self;
[self.subViews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { CGPoint thePoint = [self convertPoint:point toView:obj]; UIView *theSubHitView = [obj hitTest:thePoint withEvent:event]; if (theSubHitView != nil)
{
hitView = theSubHitView; *stop = YES;
} }]; return hitView;
}

响应链

响应链是一系列响应对象。响应链中,全部对象的基类都是UIResponder从firstResponse開始到application对象结束。firstResponse意味着首先接收到事件,一般第一响应者是一个view。对于触摸事件来说就是hit-test view。

前面说过,UIKit首先会将该事件发送给最合适的对象来处理。对于触摸事件该对象指的是hit-test view。对于其它事件。该对象指的是第一响应者。

可是实际上响应链也用在触摸事件/运动事件/远程控制事件/等

假设hit-test view无法处理一个事件。事件就通过响应链往上传递(hitTestView算是第一个Responder),直到找到一个能够处理的Responder为止。

下图给出了沿着响应链传递的顺序。两个图的差别是视图的层次关系不一样。

响应链从firstResponse開始接下来是它的父视图,假设没有父视图直到它的控制器(假设有的话)再到window和application。

initial object可能是hit-test view或者是first responder。没有处理事件。UIkit就会将该事件传递给next responder下一个响应者,每一个响应者通过调用

-nextResponder方法决定是处理该事件还是向响应链的上层传递,直到某个响应者处理了该事件或者没有响应者了为止。

不建议直接给nextResponder发消息即:

[self.nextResponder touchesBegan:touches withEvent:event];

而建议调用父类的实现。让UIKit来帮我们做,由于默认的实现是将事件沿着响应链继续向上传递到下一个responder。

[super touchesBegan:touches withEvent:event];

注:

刚開始看到hit-test view和响应链的概念有点弄混了。直到把文档好好看了一下才弄明确:当一个事件发生须要处理时。会让合适的对象去处理。假设是触摸事件的话,该对象就是hit-test view。假设是其它事件。该对象指的就是第一响应者(响应链中)。响应链是一个比較大的范畴,在触摸事件中。hit-test view就是响应链中的第一响应者。也就是说在触摸事件中通过hitTest:withEvent:方法找到的hit-test
view就是第一响应者。

Android中的事件分发

回过头简单整理了一下android里面事件传递的过程: Android之View和ViewGroup事件分发

ViewGroup传递的时候经历了dispatchTouchEvent--->onInterceptTouchEvent

从后往前遍历子View,假设子View能够处理事件返回true。

传递到此结束

假设子View不能处理该事件,自己处理....onTouchEvent

View处理事件

dispatchTouchEvent—> onTouch –-> onTouchEvent

设置监听onTouch返回了true  或者返回了false可是onTouchEvent返回true都能够觉得子View成功处理了事件

若返回了false,事件会往上抛,那么该ViewGroup会调用自己的onTouchEvent处理事件。

在iOS里面事件会由于透明度为0而不能处理/传递事件,在android里面却能够。

iOS里面假设父控件设置不能交互那么上面的子空间也不能获得事件,而android里面即使服布局设置enable为false或者clickable设置为false,上面的子空间均可接收到事件。

iOS里面没有view和view容器之分,而android里面有View和ViewGroup之分,所以事件分发也稍麻烦,

等...

感想:

学习iOS一个月,发现上手是挺快的。好多东西和android是类似的,学起来很快,可是一直困扰我的就是每当在学iOS里面新的东西的时候我总会想之前android里面是怎么实现的。两者的区别。I am so puzzled also very interested ^_^

iOS学习9_事件分发&amp;响应链的更多相关文章

  1. iOS开发事件分发机制—响应链—手势影响

    1.提纲 什么是iOS的事件分发机制 ? 一个事件UIEvent又是如何响应的? 手势对于响应链有何影响? 2.事件分发机制 2.1.来源 以直接触摸事件为例: 当用户一个手指触摸屏幕是会生成一个UI ...

  2. iOS 点击事件传递及响应

    1.iOS中的事件 iOS中的事件可以分为3大类型: 触摸事件 加速计事件 远程控制事件这里我们只讨论iOS中的触摸事件. 1.1响应者对象(UIResponder) 在iOS中不是任何对象都能处理事 ...

  3. Android事件分发与责任链模式

    一.责任链模式 责任链模式是一种行为模式,为请求创建一个接收者的对象链.这样就避免,一个请求链接多个接收者的情况.进行外部解耦.类似于单向链表结构. 优点: 1. 降低耦合度.它将请求的发送者和接收者 ...

  4. Android 进阶学习:事件分发机制全然解析,带你从源代码的角度彻底理解(上)

    http://blog.csdn.net/guolin_blog/article/details/9097463 事实上我一直准备写一篇关于Android事件分发机制的文章,从我的第一篇博客開始,就零 ...

  5. 【转载】更简单的学习Android事件分发

    事件分发是Android中非常重要的机制,是用户与界面交互的基础.这篇文章将通过示例打印出的Log,绘制出事件分发的流程图,让大家更容易的去理解Android的事件分发机制. 一.必要的基础知识 1. ...

  6. Event Delivery: The Responder Chain(事件传递,响应链)

    当我们设计app的时候,我们很可能想动态的响应事件.例如,触摸一个拥有许多不同对象的屏幕,你要决定给哪个对象一个响应事件,怎么样对象接收到事件. 当一个用户产生事件发生时(如 点击),UIKit产生一 ...

  7. 事件分发&响应链

    iOS的三种事件:触摸事件/运动事件/远程控制事件 typedef enum { UIEventTypeTouches, UIEventTypeMotion, UIEventTypeRemoteCon ...

  8. iOS-UIResponse之事件响应链及其事件传递

    UIResponse之事件响应链及其事件传递 我们的App与用户进行交互,基本上是依赖于各种各样的事件.一个视图是一个事件响应者,可以处理点击等事件,而这些事件就是在UIResponder类中定义的. ...

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

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

随机推荐

  1. document.body

    比如document.body,最好是写成document.getElementsByTagName("body")[0];

  2. HDU-5025 Saving Tang Monk 广度搜索 状态压缩

    题目链接:https://cn.vjudge.net/problem/HDU-5025 题意 救唐僧,路上有m(<=9)把钥匙,最多5条蛇和一个唐僧. 目标是前往唐僧的地方,用全部钥匙打开全部的 ...

  3. python 中i++、逻辑表达式

    参考链接:https://www.cnblogs.com/yupeng/p/3345946.html i++运算符 python中没有类似i++之类实现+1的运算符,但是有++i,+-i.之类的,他们 ...

  4. dva基本用法

    1. npm install -g dva-cli 全局安装dva.2. dva new myApp --demo 创建dva项目.3. cd myApp npm start 启动项目.4. 定义 m ...

  5. HTTP——学习笔记(7)

    HTTP中的认证机制 什么是认证机制?: 服务器需要知道客户端是谁. 怎样知道客户端身份?: 核对“登录者本人才知道的信息” 密码:只有本人才会知道的字符串信息 动态令牌:仅限本人持有的设备内显示的一 ...

  6. HDU——T 1507 Uncle Tom's Inherited Land*

    http://acm.hdu.edu.cn/showproblem.php?pid=1507 Time Limit: 2000/1000 MS (Java/Others)    Memory Limi ...

  7. Android里使用正則表達式

    在Android里怎样使用正則表達式: 以验证username为例.username一般字母开头,同意字母数字下划线.5-16个字节: String regEx = "^[a-zA-Z][a ...

  8. hdu5105Math Problem(分类讨论)

    题目链接: huangjing 题目: 思路: 给出的是一个方程,首先讨论最高项系数. 1:a==0&& b==0  那么函数就是线性的.直接比較端点就可以. 2   a==0& ...

  9. Atitit.html解析器的选型&#160;jsoup&#160;nsoup&#160;,java&#160;c#&#160;.net&#160;版本号

    Atitit.html解析器的选型 jsoup nsoup ,java c# .net 版本号 1. 框架选型的要求 1 1.1. 文档多 1 1.2. 跨平台 1 2. html解析器特性: 1 2 ...

  10. less13 颜色值函数

    //通过十进制红色,绿色,蓝色三种值 (RGB) 创建不透明的颜色对象. div{ background: rgb(255,0,0); background: rgb(100%,0%,0%); } / ...