点击事件传递及响应

301 阅读3分钟

#iOS笔记/复习笔记

问题:为什么手势和单击事件只会响应手势? UIGestureRecognizer有个属性cancelsTouchesInView,这个属性默认为yes,当手势识别成功后,会发送touchesCancelled消息为view来结束view的响应。如果cancelsTouchesInView为NO,那么gestureRecognizer和view都可以响应。;

事件的传递

  1. 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的队列事件中;
  2. UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常会先发送事件给应用程序的主窗口(keyWindow)
  3. 主窗口会在视图层次机构中找到一个最合适的视图来处理触摸事件;
    1. 首先判断主窗口(keyWindow)自己是否能接受触摸事件
    2. 触摸点是否在自己身上;
    3. 从后往前遍历子控件,重复前面的两个步骤;
    4. 如果没有符合条件的子控件,那么就认为自己最合适处理; 详述:
    5. 主窗口接受到应用程序传递过来的事件后,首先判断自己能否接受触摸事件,如果能,那么再判断触摸点在不在窗口自己身上;
    6. 如果触摸点在窗口上,那么窗口会从后往前遍历自己的子控件(遍历自己的子控件只为了寻找出来最合适的view)
    7. 遍历到每一个子控件后,又会重复上面两个步骤(传递事件给子控件,1.判断子控件能否接受事件,点在不在子控件上);
    8. 如此循环遍历子控件,直到找到最合适的view,如果没有更合适的子控件,那么自己就成为最合适的view。 注意:之所以会才去从后往前遍历子控件的方式寻找,只是为了做一些循环优化。因为相比较之下,后面添加的view在上面,降低循环次数。

在事件传递寻找最合适的view时,底层到底干了哪些事?

寻找合适的view用到两个重要方法:

hitTest:withEvent: 
pointInside:withEvent

只要事件传递给一个控件,这个控件就会调用他自己的hitTest:withEvent:方法来寻找合适的view; 注意:不管这个控件能不能处理事件,也不管触摸点在不在这个控件上,事件都会先传递给这个控件,随后再调用hitTest:withEvent:方法;

事件的响应

这里有一个响应者链条:响应者链条其实就是很多响应者对象,一起组合起来的链条; 如何判断当前的响应者的上一个响应者是谁,有两个规则:判断view是不是当前控制器的view,如果是则上一个响应者就是控制器;如果不是,上一个响应者就是父控件;

touch响应:

  • 找到最合适的view,调用touches方法处理事件;(如果没有重写touchesBegin,自己就处理不了触摸事件)
  • touches默认做法是把时间顺着响应者链向上抛;

事件的传递和响应的区别: 事件的传递是从上到下(父控件到子控件),事件的响应是从下到上(顺着响应者链条向上传递:子控件到父控件)。

iOS 点击事件传递及响应 - 简书