事件分发机制
事件分发机制 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 从底层向上寻找
事件传递
第一步确定好了处理事件的hit-test , 接着就是处理事件的顺序, 正好跟事件的分发机制相反, 最有机会处理事件的对象是hit-test视图或第一响应者. 如果这两个都不能处理事件 , UIKit就会将事件传递到响应链中的下一个响应者. 每一个响应者确定其是否要处理事件或者通过nextResponder方法将其传递给下一个响应者 . 这一过程一直持续到走到能处理事件的响应者对象, 或者最终没有找到响应者.
视图事件传递 从最上层往下传递
响应链
例如: 微信点击 扫一扫 就打开二维码扫描视图
在我们点击屏幕的时候 , iPhoneOS获取到了用户进行了”单击”行为, 操作系统将包含这些点击事件的信息包装成UITouch或者UIEvent形式的实例, 然后找到当前运行的程序,逐级寻找能够响应这个事件的对象,直到没有响应者响应. 这一寻找过程 被称作事件的响应链 .
总结: 某个控件在接收到点击事件时的处理
hitTest:withEvent:
方法的处理流程
先调用pointInside:withEvent:
判断触摸点是否在当前视图内
如果返回 YES,那么该视图的所有子视图调用
hitTest:withEvent
,调用顺序由层级低到高(top->bottom)依次调用。如果返回 NO,那么
hitTest:withEvent
返回nil,该视图的所有子视图的分支全部被忽略
如果某视图的pointInside:withEvent:
返回YES,并且他的所有子视图hitTest:withEvent:
都返回nil,或者该视图没有子视图,那么该视图的hitTest:withEvent:
返回自己。
如果子视图的hitTest:withEvent:
返回非空对象,那么当前视图的hitTest:withEvent:
也返回这个对象,也就是沿原路回推,最终将hit-test view
传递给keyWindow
Demo
效果 ==> 点在贝塞尔曲线内才能处理touch事件:
点在不在规定的区域内??? 如果是就返回YES,不是返回NO
LLSHitTestView 是一个测试hitTest返回的View的类