Button 被点击之后,分为两部分:一个是事件的传递,一个是响应的传递.即传递链和响应链.
大体意思就是:先找点的是哪个view,然后再决定由哪个view来响应这个事件.
首先我们来看传递链:
传递链中有两个核心的方法:
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event; // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; // default returns YES if point is in bounds
hitTest 会返回一个View,用来寻找到底哪一个view来响应. pointInside 来判断当前的点是否存在某个视图内部.
当alpha = 0 或者 hidden = Yes 或者 userInter 属性为NO 的时候都是不处理事件的.
事件传递流程: 1.将点击事件加到Applicaton维护的任务队列中,然后取最顶部的事件进行处理,向下分发.
2.来到window,然后就开始递归调用hitTest 来寻找响应的View,找到之后通过pointInside:来判断当前的点在那个subview里面,并决定是否响应.
3.遍历子视图,是倒序遍历 ,也就是最后被添加的视图,会最先被遍历.在每一个视图中都回去调用它的hitTest:withEvent:方法,可以理解为是一个递归调用
4.最后看hitTest是否返回vIEW 如果有那就响应事件,并结束当前的事件传递.
事件响应流程
1.如果view 的控制器存在,就传递给控制器处理,如果控制器不存在,就传给他的父视图.
2.在视图结构的最顶层,如果也不能处理收到的事件,那就传给uiwindow.
3.如果uiwindow也不能处理,那就给uiapplication.
4.如果application 也不能处理那就,舍弃.
实例场景
指定一个view的指定一个圆形区域响应区域. 例如: UIView *tagertV = [UIView new]; 首先判断当前点击的点,是否在view的里面.
-
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 获取当前点点击坐标.
-
通过 -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 来指定响应区域.