IOS事件分发、Responder Chain(一)——hit-testing

在IOS系统中,用户会触发若干事件,系统会分发这些事件,并交由恰当的对象来处理。IOS事件分发流程大致如下:

1、用户触发事件,系统将事件封装为event object对象,放入当前APP的event queue中。(touch事件对应的event object包含了一系列的touch对象,而motion对应的event则因事件不同而不同)

2、由当前APP对应的单例对象UIApplication在queue头中取出event object,分发至当前APP的主window object

3、主window object会将event object分发至当前最合适的initial object来处理。(对于touch event,initial object为hit-test view, 对于motion,remote control,initial object为first responder)

4、当然initial object也可以不处理该event,这样,event object会沿着一条规定的路径一路向上传递直到有object可以处理该event,或者抛弃该event。而这个向上寻找对应的处理event的object的路径,叫做Responder Chian。它始于initial object,终于application object。该chain上的所有对象,均继承与UIResponder,通过nextResponder方法,可以找到当前对象响应链上的下一个对象。

hit-testing 与 hit-test view

如前所述,当主window对象分发event object时,若event object为touch event,则最终hit-test view获得最先响应touch事件权利,而判断hit-test view的过程,叫做hit-testing。

hit-testing是一个递归的过程,执行过程如下

1、判断touch point是否在当前view中

2、若在,这继续判断touch point是否在当前view的子view中,若不在,则直接返回,不在继续判断。

3、这样一直递归判断,直到touch point所在的最底层的subview,并返回该subview作为响应touch event的hit-test view。

4、确定了hit-test view,系统将会使touch event交由该view处理,若该view没有处理该事件,则touch event会沿着Responder Chain一路向上寻找可以响应touch event的Responder。


在hit-testing中,系统会调用每个view的hitTest:withEvent: 方法,该方法最终会返回一个view作为hit-test view。而在hitTest:withEvent: 方法中,view又会调用 pointInside:withEvent:来测试当前view是否在touch的范围内,若是,则 pointInside:withEvent:返回YES,系统继续依次调用subview们的hitTest:withEvent: 方法,若pointInside:withEvent:返回NO,则hitTest:withEvent: 直接返回nil。


注意到hitTest:withEvent: 上面的这种实现,那么有一种情况是当subview的范围超出父view时,若touch是发生在超出的那块区域,则subview默认不会得到响应touch event的机会,因为在其父view判断 pointInside:withEvent:就已经返回了NO,hitTest:withEvent: 不会继续向下判断。


Apple网站上的这么一段说明,很好的解释了hit-testing的过程:

To illustrate, suppose that the user touches view E in Figure 2-1. iOS finds the hit-test view by checking the subviews in this order:

  1. The touch is within the bounds of view A, so it checks subviews B and C.

  2. The touch is not within the bounds of view B, but it’s within the bounds of view C, so it checks subviews D and E.

  3. The touch is not within the bounds of view D, but it’s within the bounds of view E.

    View E is the lowest view in the view hierarchy that contains the touch, so it becomes the hit-test view.

Figure 2-1   Hit-testing returns the subview that was touched



了解了上面hit-testing的判断过程,下面就有一个有趣的问题:

如图,绿色的view是红色view的subview,那么当我在蓝点所示的位置点击屏幕时,绿色view是否能够获取到该事件呢?

答案是否定的,因为系统在进行hit-testing时,会首先判断事件发生的point是否在其父view,即红色view范围内。很明显,point并不在红色view中,因此系统就放弃了继续判断其绿色子view是否在事件范围内。若想使得sub view一定要有所相应,那么应该设置父view的

clipsToBounds属性为YES,强制子view在父view的范围内显示。


参考资料

https://developer.apple.com/library/prerelease/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/event_delivery_responder_chain/event_delivery_responder_chain.html#//apple_ref/doc/uid/TP40009541-CH4-SW4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值