GeekBand - iOS 事件传递及响应笔记第一周

2016-09-12  本文已影响79人  varlarzh

本次笔记主要是整理一下关于 iOS 中关于事件传递和响应机制,参考了一些其他资料加上自己的理解。

事件 Events

定义是 objects sent to an app informing user actions.

iOS 中的事件

iOS 有三种事件类型:

响应者对象 UIResponder

在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接受并处理事件,我们称之为“响应者对象”。以下都是继承自UIResponder的,所以都能接收并处理事件。

以上三个类都继承自 UIResponder ,所以都可以接收并处理事件。

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;
//加速计事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
//远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

当用手指触摸 UIView 的一个实例的时候,就会产生触摸事件 UIEventTypeTouches,而接收对象 UIView 就是一个Responder object。 一个事件可以被多个 Responder 接收,第一个接收事件的对象就是 firstResponder。

触摸事件

UIView 的触摸事件处理方法有以下几种:

// UIView是UIResponder的子类,可以覆盖下列4个方法处理不同的触摸事件
// 一根或者多根手指开始触摸view,系统会自动调用view的下面方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
// 一根或者多根手指在view上移动,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
// 一根或者多根手指离开view,系统会自动调用view的下面方法- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
// 触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用view的下面方法
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
// 提示:touches中存放的都是UITouch对象

以上四个方法是由系统自动调用的,所以可以通过重写该方法来处理一些事件。需要注意的是重写以上四个方法,如果是处理UIView的触摸事件,必须要自定义UIView子类继承自UIView。没有UIView的 .m 文件,只能通过子类继承父类,重写子类方法的方式处理UIView的触摸事件。如果是处理UIViewController的触摸事件,那么在控制器的.m文件中直接重写即可。

UIView 的拖拽事件

实现拖拽是让UIView随着手指的移动而移动,重写touchsMoved:withEvent:,需要用到UITouch对象。

UITouch对象的作用:

UITouch 对象的属性

UITouch 的方法

iOS 中事件的产生和传递

事件传递

举例:


UIEvent

找到最合适的 view 后,就会调用该 View 的 touches 方法处理具体的事件,只有找到最合适的 View,把事件传递给 View 后才会调用 touches 等方法来进行事件处理。

具体如何找到最合适的 View 来处理事件

整个过程类似递归调用。
举例说明,假如点在黄色 View 上,触摸事件是从父控件传递到子控件,UIApplication -> UIWindow -> 白色 -> 橙色 -> 蓝色 -> 黄色。点在黄色View上,同时也点在白色、橙色和蓝色上,系统如何判断是点在黄色上呢?首先点到黄色后会产生一个触摸事件,系统会将该事件 UIEvent 加入到一个由 UIApplication 管理的事件队列中,UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow),主窗又会在视图层次结构中找到一个最合适的视图来处理触摸事件。关键来了,UIWindows首先判断自己是否接收触摸事件,及触摸点是否在自己身上,这两点满足后,便开始从后往前遍历子控件,注意此时 UIWindow 的子控件只有白色 View,然后判断白色 View 是否满足 1.自己是否接收触摸事件 2.触摸点是否在自己身上,两点满足后开始执行 3.从后往前遍历子控件。此时白色 View 有两个子控件,绿色 View 和橙色 View,按照从后往前,即后添加的橙色 View 。先判断橙色 View 的是否满足三个条件,橙色判断完后在判断绿色,绿色判断的时候不满足触摸点在自己身上,终止。橙色判断满足前两条,然后开始第三条,遍历橙色的子控件,然后红色不满足,蓝色继续判断,前两条满足,然后遍历蓝色的子控件,只有黄色 View,此时黄色满足2条,但是没有子控件,循环停止,最终返回的就是黄色 View。可以看出,如果父控件不能接收触摸事件,触摸事件是不能传递到子控件的。

底层实现

两个方法

hitTest:withEvent: 方法用来寻找并返回最合适的 View,可以通过重写该方法返回指定的 View 作为最合适的 View。这样可以拦截事件的传递过程,指定 View 来处理事件。

事件传递给谁就会调用谁的hitTest:withEvent:方法,如果hitTest:withEvent:方法中返回nil,那么调用该方法的控件本身和其子控件都不是最合适的 view,也就是在自己身上没有找到更合适的 view。那么最合适的 view 就是该控件的父控件。

事件传递给窗口或控件后,首先要调用hitTest:withEvent:方法来寻找最合适的 View。其过程是先传递事件,view 接收到该事件后开始调用hitTest:withEvent:方法。假如层级结构A->B->C,A是最顶层的 View,A收到事件后,会根据hitTest:withEvent:来查找最合适的 View,此时会返回自己为合适的 view,要查找最合适的 View 就需要继续传递事件,即使 A 是最合适的 View,也需要进一步传递事件,因为此时还不知道自己是最合适的 View,将事件传递给 B 之后,B 就会调用自己的 hitTest:withEvent: 方法来查找最合适的 View,仍然返回自己为合适的 View,继续寻找最合适的 View,然后事件传递给 C,C 调用后有子控件,则 C 就是最合适的 View。

想让谁成为最合适的view就重写谁自己的父控件的hitTest:withEvent:方法返回指定的子控件。

hit:withEvent:方法底层会调用pointInside:withEvent:方法判断点在不在方法调用者的坐标系上。

UIView 不接收触摸实践的三种情况

事件的响应

上述的事件传递,只是根据 View 是否接收触摸事件及触摸点的位置来找到最合适的 View 来处理事件,找到最合适的 View 后会调用 touches 等方法来作具体的事件处理,但是最合适的 View 可能不具备 touches 方法来处理事件,此时机会存在一个事件响应的问题,最合适的 View 不一定能响应该事件,引出了响应链的传递过程,一般是讲事件交给上一个响应者来进行处理。

响应者链条示意图

响应链条示意图

事件传递的完整过程

  1. 先将事件对象由上往下传递(由父控件传递给子控件),找到最合适的控件 来处理这个事件。
  2. 调用最合适控件的touches....方法
  3. 如果调用了[super touches....];就会将事件顺着响应者链条往上传递,传递
    给上一个响应者
  4. 接着就会调用上一个响应者的touches....方法

如何判断上一个响应者

响应者链的事件传递过程

事件的传递和响应

** 事件的传递和响应的区别:**

Demo

关于事件传递和响应链条的小Demo:事件传递及响应Demo

上一篇下一篇

猜你喜欢

热点阅读