扬庆の博客

iOS 事件分发机制

字数统计: 883阅读时长: 3 min
2021/04/02 Share

事件分发机制

事件分发机制 hit-Testing.

当我们点击了iOS设备的屏幕 , UIKit 就会生成一个事件对象UIEvent , 然后会把这个event分发给当前active活动的app.

告知当前活动的app有事件以后 , UIApplication单例就会从事件队列中去取最新的事件 , 然后分发给能够处理该事件的对象 . 这些事件按照先进先出的顺序来处理. 当处理事件时,程序的UIApplciation对象会从队列头部取出一个事件对象 , 将其分发出去 .UIApplication获取到Event后 , Application就纠结于到底要把这个事件传递给谁,这时候就要依靠HitTest 来决定了.

app - UIApplication - 拿到 UIEvent - 传递给视图

iOS中,hit-Testing 的作用就是找出这个触摸点下面的view是什么, HitTest会检测这个点是不是发生在这个View上, 如果是的话,就会去遍历这个view的subviews,直到找到最小的能够处理事件的view , 如果整了一圈没有找到能够处理的view, 则返回自身 . 最后(确定了hit-TestView) UIApplication会将事件给这个view进行处理.

找到处理事件的 view 从底层向上寻找

hitTest


事件传递

第一步确定好了处理事件的hit-test , 接着就是处理事件的顺序, 正好跟事件的分发机制相反, 最有机会处理事件的对象是hit-test视图或第一响应者. 如果这两个都不能处理事件 , UIKit就会将事件传递到响应链中的下一个响应者. 每一个响应者确定其是否要处理事件或者通过nextResponder方法将其传递给下一个响应者 . 这一过程一直持续到走到能处理事件的响应者对象, 或者最终没有找到响应者.

视图事件传递 从最上层往下传递

reponse chain

响应链

例如: 微信点击 扫一扫 就打开二维码扫描视图

在我们点击屏幕的时候 , iPhoneOS获取到了用户进行了”单击”行为, 操作系统将包含这些点击事件的信息包装成UITouch或者UIEvent形式的实例, 然后找到当前运行的程序,逐级寻找能够响应这个事件的对象,直到没有响应者响应. 这一寻找过程 被称作事件的响应链 .

总结: 某个控件在接收到点击事件时的处理

hitTest:withEvent:方法的处理流程

先调用pointInside:withEvent:判断触摸点是否在当前视图内

  1. 如果返回 YES,那么该视图的所有子视图调用hitTest:withEvent,调用顺序由层级低到高(top->bottom)依次调用。

  2. 如果返回 NO,那么hitTest:withEvent返回nil,该视图的所有子视图的分支全部被忽略

如果某视图的pointInside:withEvent:返回YES,并且他的所有子视图hitTest:withEvent:都返回nil,或者该视图没有子视图,那么该视图的hitTest:withEvent:返回自己。

如果子视图的hitTest:withEvent:返回非空对象,那么当前视图的hitTest:withEvent:也返回这个对象,也就是沿原路回推,最终将hit-test view传递给keyWindow

Demo

效果 ==> 点在贝塞尔曲线内才能处理touch事件:

点在不在规定的区域内??? 如果是就返回YES,不是返回NO

touchbegin

LLSHitTestView 是一个测试hitTest返回的View的类

参考iOS-hitTest:withEvent与自定义hit-testing规则

CATALOG
  1. 1. 事件分发机制
    1. 1.0.1. 事件分发机制 hit-Testing.
    2. 1.0.2. 事件传递
      1. 1.0.2.1. 响应链
    3. 1.0.3. hitTest:withEvent:方法的处理流程
    4. 1.0.4. Demo