ios触摸事件响应链个人总结

hit-test view

当用户手指在屏幕上触摸时,系统会检测到用户触摸并将触摸信息包装成事件放入应用的Run loop中等待被处理。待UIApplication单例处理完手头工作后,将事件从Run loop中取出,并发送给UIWindow单例。UIWindows单例通过递归调用hittest:withEvent:方法找到触摸所在视图,此时这个视图就称作hit-test view。找到hit-test view后,UIWindow把事件交给其处理。一般来说,这个视图此时就是first responder(第一响应者)。

在如下图所示的视图层次中,假设用户触摸的时E视图,在调用hittest:withEvent:

hit-test

  1. 首先对A进行测试,返回YES,继续对BC进行测试
  2. B测试返回NO,不再继续往下测试,转而对C进行测试
  3. C测试返回YES,继续对DE进行测试
  4. D测试返回NO,不再继续往下测试,转而对E进行测试
  5. E测试返回YES,由于E是最低一级视图,所以hittest:withEvent:返回视图E

在调用hittest:withEvent:时会传入两个参数:一个GCPoint和一个UIEventGCPoint表示手指触摸屏幕时的坐标,UIEvent包装了此次触摸的触摸事件。hittest:withEvent:执行时会首先对自己调用pointInside:withEvent:来测试GCPoint是否在自己的bounds范围内,如果在,返回YES并继续对自己的子视图递归调用hittest,不在返回NO并且hittest:withEvent:返回nil

一旦hittest:withEvent:返回nil的话就不会再继续对其子视图调用hittest:withEvent

通过hittest:withEvent:找到的hit-test view将有第一次机会去处理触摸事件,如果不能够处理的话,将会把事件沿着响应者链往下传递来找到能够处理事件的对象。

如果在UIView上附加了UIGestureRecognozer可能会使UIWindow延迟或取消向UIView发送事件而由UIGestureRecognozer进行接收识别并交由UIGestureRecognozertarget进行处理

响应者链

first responder

响应者链中第一个有机会处理事件的对象叫做first responder(第一响应者)。

first responder通常是一个UIView对象。

触摸事件中,frist responder通常是hit-test view

如果要让一个对象成为第一响应者,要做到以下两件事情:

  1. 重写canBecomeFirstResponder方法并返回YES
  2. 调用becomeFirstResponder方法

应该在视图出现之后调用becomeFirstResponder方法,比如说在viewDidAppear方法中调用becomeFirstResponder方法。如果在视图还未出现之前调用becomeFirstResponder方法的话将会失败,比如说在viewWillAppear中调用becomeFirstResponder方法将会返回NO

事件传递

响应者链由一系列UIResponder的子类组成,并且其末尾为UIApplication单例。如果响应者链中的某个对象不能处理事件,事件将沿着响应者链向上进行传播。如果链上的所有对象都不能处理事件,事件最终会传播到UIApplication单例对象,如果UIApplication单例对象也不能进行处理,那么事件最终会被丢弃。

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

并且一般来说

  1. 如果一个UIView有它自己的UIViewController的话那么它的nextResponder就是它的UIViewController,否则就是它的父视图
  2. UIViewControllernextResponder是它的view的父视图
  3. 根视图或根试图控制器的nextResponderUIWindow
  4. UIWindownextResponderUIApplication

因为响应者链中的所有的对象都是UIResponder的子类,因此,当某个事件无法处理并且要交给下一个响应对象处理的时候应该调用

[super touchesXXX:touches withEvent:event];

而不是

[self.nextResponder touchesXXX:touches withEvent:event];

因为调用后者可能会漏掉父类对事件的一些其他的处理。

大致的事件传递流程可以参考下图

responder chain

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值