iOS中touch事件传递(响应者链)
前言:
不知不觉开发iOS三年之多了,成功的从一个小菜鸟变成了大菜鸟,前些日子面试被问到: iOS中事件传递是怎么样的,touch事件苹果是如何收集的? 由于之前没有了解过这些原理以及实现.一直本着能用就行.遇到这种问题直接懵逼了.
后来通过阅读相关文章简单总结了一下,希望可以帮助到更多同学!!!希望共同成长
在iOS中凡是继承自UIResponder的对象都能够接收并处理事件
•先说如何会产生touch事件
1.触摸事件(例如点击,滑动,缩放等)
2.加速计事件(例如摇微信一摇,指南针等)
3.远程控制事件(例如蓝牙,wifi)
1.触摸事件:
当手指触摸手机屏幕时,系统会调用view的
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event方法
当手指在手机屏幕上移动时,系统会调用view的
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event方法
当手指离开手机屏幕时,系统会调用view的
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event方法
每个方法中的touches参数是NSSet类型(也就是集合类型),里边存放的是一个或多个UITouch对象,当手指触摸到屏幕时候会创建UITouch对象(一个手指对应一个UITouch对象),每个UITouch对象中存放的是这个动作的相关信息(触摸次数,视图大小,位置,类型等相关信息)
当手指离开屏幕后,集合里保存的UITouch对象也会随之销毁.
那我们来看看这些动作是怎么实现的,首先我们来看事件是怎么传递的
发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的队列事件中,UIApplication会从事件队列中取出最前边的事件分发下去处理,会先发生给窗口视图KeyWindow
视图会一层一层向上寻找最合适的视图来处理事件.找到合适的视图后会调用该视图的Touch方法(也就是上边说到的touchBegin,touchMove等)去做处理.也就是说该事件传递是从父视图依次向子视图传递的.如果父视图不能够接收并处理事件,那么他的子视图就不能接收并响应事件.
以下几种情况View不能接收并响应事件
1.view.userInteractionEnabled = NO;(不可交互)
2.view.hidden = YES;(隐藏)
3.view.alpha <=0.01;(透明度小于等于0.01)
那么如何找到最合适的视图?
1.自己本身是否可以接收事件
2.触摸点是否在本身范围内
3.查看自己的子控件是否可以接收事件
4.查看触摸到是否在自己的子控件上
5.如果没有就在自己本身处理
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 这个方法就是用来查找最合适处理事件的方法,和-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event配合使用(判断触摸到是否在自身上).
通过上边的步骤.我们可以自己来模拟一下寻找view的实现
最后总结来说一次完整的触摸事件的传递响应过程为:
UIApplication-->UIWindow-->递归找到最合适处理的控件-->控件调用touches方法-->判断是否实现touches方法-->没有实现默认会将事件传递给上一个响应者-->找到上一个响应者-->找不到方法作废
最后我们还可以使用响应者链找到当前视图
- (UIViewController *)parentController
{
UIResponder *responder = [self nextResponder];
while (responder) {
if ([responder isKindOfClass:[UIViewController class]]) {
return (UIViewController *)responder;
}
responder = [responder nextResponder];
}
return nil;
}