2.2 谈谈你对事件的传递链和响应链的理解

一.响应者链

响应者链UIResponser 包括了 触摸信息的处理,比如开始、移动、停止等等。常见的UIresponser有UIView及其子类,UIViewController,AppDelegate,UIApplication等等。

响应者链是由UIResponser组成的。,他是是按照哪种规则组成的呢?

A: 程序启动UIApplication会生成一个单例,并会关联一个APPDelegate。AppDelegate作为整个响应链的根建立起来,而UIApplication会将自己与这个单例链接,即UIApplication的下一个responser为AppDelegate。

B:创建UIWindow程序启动后,任何的UIWindow被创建时,UIWindow内部都会吧nextResponser 设置为UIApplication单例。UIWindow初始化rootViewController,rootViewController的nextResponser会设置为UIWindow。

C:UIViewController初始化loadView VC的view的nextResponser会设置为VC。

D:addSubView的过程中,如果subView不是VC的View,那么subView的nextResponser会被设置为superView。如果是VC的View,那就是 subView -> subView.VC ->superView如果在中途,subView.VC被释放,就会变成subView.nextResponser = superView

二.事件传递链

事件传递通过两种方法来做这个事情。

// 先判断点是否在View内部,然后遍历subViews

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;  

//判断点是否在这个View内部

- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;  

流程

1:先判断该层级是否能够响应(1.alpha>0.01 2.userInteractionEnabled == YES 3.hidden = NO)

2:判断该点是否在view内部    ,

3:如果在那么遍历子view继续返回可响应的view,直到没有。

hitTest:withEvent:方法的处理流程如下:

首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;

若返回NO,则hitTest:withEvent:返回nil;

若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;

若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;

如所有子视图都返回非,则hitTest:withEvent:方法返回自身(self)。

常见问题

1.父view设置为不可点击,子view可以点击吗

回答:不可以,hit test 到父view就截止了

子view设置view不可点击不影响父类点击

实际用法

点一一个圆形控件,如何实现只点击圆形区域有效,重载pointInside。此时可将外部的点也判断为内部的点,反之也可以。

事件响应链在复杂功能界面进行不同控件间的通信,简便某些场景下优于代理和block

你可能感兴趣的:(2.2 谈谈你对事件的传递链和响应链的理解)