什么是触摸事件
触摸事件发生后,系统会将触摸事件添加到由UIApplication管理的队列中(为什么是队列,因为队列是FIFO,先进先出,先发生的事件,优先处理),再由UIApplication向下传递给UIWindow,UIWindow继续向下传递给他的子控件,直到找到最优的控件,这个过程称之为事件传递。
学习事件传递,首先要搞清楚一个概念---触摸对象
什么是触摸对象
继承自UIResponder的都具备事件处理能力,如UIApplication、UIWindow、UIView。都可以处理事件。
如何找到最合适的view
- 首先判断uiwindow能否处理事件
- 触摸点是否在自己身上
- 子控件数组从后往前遍历子控件,重复前面的两步操作(首先判断uiwindow能否处理事件,触摸点是否在自己身上)
- 遍历子控件的子控件数组,如果没有合适的view,直到找不到合适的view
- 如果没有符合条件的子控件,那么认为自身就是最合适的控件
控件能够处理事件需要满足三个条件
- 隐藏:hidden是否等于YES,等于YES不能处理事件;
- 交互能力:userInteractionEnabled是否等于No,等于NO ,不能处理事件,;
- 透明度:控件的透明度是否<0.01,小于0.01不能处理事件;
无论控件能否处理事件,事件都会传递给控件,并调用hittest方法,
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (self.userInteractionEnabled == NO || self.alpha < 0.01 | self.hidden == YES) {
return nil;
}
if ([self pointInside:point withEvent:event] == NO) {
return nil;
}
//获取子控件数组
NSArray *subViewsArray = self.subviews;
//遍历子控件数组
for (int i = 0; i < subViewsArray.count; i++) {
//倒序遍历子控件数组
UIView *view = self.subviews[subViewsArray.count - 1 - I];
//将触摸点转化为子控件的触摸点
CGPoint npoint = [self convertPoint:point toView:view];
//调用子控件的hittest方法寻找最合适的view
UIView *fitView = [view hitTest:npoint withEvent:event];
//如果有最合适的view,返回最合适的view
if (fitView) {
return fitView;
}
}
//如果子控件中没有最合适的view,则自身就是最合适的
return self;
}
响应者链
响应者链,顾名思义,就是由一个个响应者组成的链条,首先由最优的view向上传递,传递给下一个响应者,如果所有的响应者都不能响应事件,则事件被丢弃。
与事件传递方向正好相反,事件传递是由上向下传递,响应者链是由下向上传递。
- 如果当前view是控制器的view,那么他的下一个响应者就是当前控制器
- 如果当前view不是控制器的view,那么他的下一个响应者就是他的父视图
事件不响应的几种情况
- 控件超出父控件范围
- 子控件有相同的方法,发生事件拦截(cell上的子控件添加点击事件后,cell的点击事件将不会响应)
- 控件或者父控件的userinterfaceennable为No,
网友评论