iOS事件传递和响应机制

208 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

事件的产生

发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中,为什么是队列而不是栈?因为队列的特点是FIFO,即先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列。

UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。

主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。

找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。

事件的传递

触摸事件的传递是从父控件传递到子控件

也就是UIApplication->window->寻找处理事件最合适的view

注 意: 如果父控件不能接受触摸事件,那么子控件就不可能接收到触摸事件

应用如何找到最合适的控件来处理事件?

1. 首先判断主窗口(keyWindow)自己是否能接受触摸事件
2. 判断触摸点是否在自己身上
3. 子控件数组中从后往前遍历子控件,重复前面的两个步骤(所谓从后往前遍历子控件,就是首先查找子控件数组中最后一个元素,然后执行1、2步骤)\
4. 如果没有符合条件的子控件,那么就认为自己最合适处理这个事件,也就是自己是最合适的view。

寻找最合适的view底层剖析

两个重要的方法:

  • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
  • (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

hitTest:withEvent 方法介绍

什么时候调用?

只要事件一传递给一个控件,这个控件就会调用他自己的hitTest:withEvent:方法
作用

寻找并返回最合适的view(能够响应事件的那个最合适的view)
注 意
1.不管这个控件能不能处理事件,也不管触摸点在不在这个控件上,事件都会先传递给这个控件,随后再调用hitTest:withEvent:方法
2.如果hitTest:withEvent:方法中返回nil,那么调用该方法的控件本身和其子控件都不是最合适的view,也就是在自己身上没有找到更合适的view。那么最合适的view就是该控件的父控件。

pointInside:withEvent 方法介绍

判断点在不在当前view上(方法调用者的坐标系上)如果返回YES,代表点在方法调用者的坐标系上;返回NO代表点不在方法调用者的坐标系上,那么方法调用者也就不能处理事件。

UIView不能接收触摸事件的三种情况:

  • 不允许交互:userInteractionEnabled = NO
  • 隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件
  • 透明度:如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。alpha:0.0~0.01为透明。