参考文章:
iOS触摸事件的流动
UIViewController UIApplication UIView 都继承了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;
一 触摸事件的产生与传递
找: 从父视图往子视图 倒序遍历查找最适合的responder
1.首先判断 自己是否能接受触摸事件
2.判断触摸点是否在自己身上
3.子控件数组中从后往前遍历子控件,重复前面的两个步骤(所谓从后往前遍历子控件,就是首先查找子控件数组中最后一个元素,然后执行1、2步骤)
4.view,比如叫做fitView,那么会把这个事件交给这个fitView,再遍历这个fitView的子控件,直至没有更合适的view为止。
5.如果没有符合条件的子控件,那么就认为自己最合适处理这个事件,也就是自己是最合适的view。
其中以下三种情况则会阻断查找,自己和自己的所有子视图都不会是那个合适的responder
1.userInteractionEnabled = NO
2.alpha < 0.01
3.hidden = YES
触摸事件// 什么时候调用:只要事件一传递给一个控件,那么这个控件就会调用自己的这个方法// 作用:寻找并返回最合适的view// UIApplication -> [UIWindow hitTest:withEvent:]寻找最合适的view告诉系统// point:当前手指触摸的点// point:是方法调用者坐标系上的点
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event{
// 1.判断下窗口能否接收事件
if(self.userInteractionEnabled ==NO||self.hidden ==YES||self.alpha <=0.01) return nil;
// 2.判断下点在不在窗口上// 不在窗口上
if([selfpointInside:point withEvent:event] ==NO) return nil;
// 3.从后往前遍历子控件数组
intcount = (int)self.subviews.count;for(inti = count -1; i >=0; i--) {
// 获取子控件
UIView*childView =self.subviews[i];
// 坐标系的转换,把窗口上的点转换为子控件上的点
// 把自己控件上的点转换成子控件上的点
CGPointchildP = [selfconvertPoint:point toView:childView];UIView*fitView = [childView hitTest:childP withEvent:event];
if(fitView) {
// 如果能找到最合适的viewreturn fitView;
}
}
// 4.没有找到更合适的view,也就是没有比自己更合适的view
return self;
}// 作用:判断下传入过来的点在不在方法调用者的坐标系上// point:是方法调用者坐标系上的点
//- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
//{
// return NO;
//}
二 事件响应过程
当找到这个最合适的视图,看它是否重写了touchBegan等方法或者有 UIGesture等手势。先执行重写的touchBegan方法 ( 滑动 - moved方法), 若有手势再执行手势的action,最后执行 touchCancled方法。终止。
如果都没有,就调用默认实现 super touchXXX 将事件交给上一个响应者。
注意VC.view 根视图的上一个响应者是 VC
事件响应链
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{//调用super 就是将事件沿着响应者链条往上传递
[super touchesBegan:touches withEvent: event];
}
两个关键的方法能做什么用
(1).在自定义的父类中写 如下代码 可以在这个父类View frame 内所有的触摸事件执行前 先执行xxxx ,并且不打断 子控件 的交互
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event{
[self xxxx];
[super hitTest:point withEvent:event ];
}
(2).touch等方法中先执行xxx,然后再将事件传递给 上一个响应者 如果上一个响应者即写了 touchBegan 又加了手势, 那么会再执行完上一个响应者的touchBegan后,执行手势的action,然后执行上一个响应者的 touchCancled,再执行自己的touchCancled
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event
{
[self xxx];
[supertouchesBegan:toucheswithEvent:event];
}
未完待续: 手势理解明天再写。
网友评论