前言

素日咱们在玩手机,当咱们的手指点击的当人手在点击屏幕时,体系会依据咱们的手指动作产生一个触屏事情,这个事情能够是点击、拖动、缩放等手势,咱们统称为触屏事情。那么体系是如何依据触屏事情去呼应咱们想要的成果呢?

一、根本元素了解

想要知道体系是怎样呼使用户的触屏事情,需求提早知道3个与用户界面事情相关的类,它们别离是UITouchUIEventUIResponder

UITouch

一个手指接触会生成一个UITouch目标,多个手指接触会生成多个UITouch目标。查看官方文档,其界说如下:

iOS |关于触摸事件的传递机制以及响应流程

图中的特点和意义别离表明

  1. timestamp:接触事情产生的时刻戳,单位是秒(s)
  2. phase:接触事情的阶段,即接触事情的状况(例如began、end、cancel
  3. tapCount:短时刻内接触的点击次数,用来判别单击,双击等
  4. type:接触类型,例如手指接触或笔接触(ios9.0可用)
  5. majorRadius:接触的主轴半径,一般用于辨认接触点的大小和形状(ios8.0可用)
  6. majorRadiusTolerance:接触的主轴半径容差,一般用于确认接触点的大小和形状的变化规模(ios8.0可用)
  7. window:接触地点的窗口
  8. view:接触地点的视图
  9. gestureRecognizers:是一个数组,包含了与当时接触点相关的一切手势辨认器目标,但是并不包含其他视图或窗口中的手势辨认器目标(ios3.2可用)

UIEvent

UIEvent是一切用户界面事情的基类,包含触屏事情、手势事情、按键事情等,每个UIEvent供给事情类型、事情产生时刻、事情涉及到的接触目标等信息。UITouch目标则是UIEvent目标中的一部分,表明了用户当时的触屏信息。它首要包含以下特点:

iOS |关于触摸事件的传递机制以及响应流程

  1. type:表明事情的类型,例如接触、按压、滚动
  2. subtype:表明事情的子类型,用于进一步描述事情的类型。例如上面的type的值是接触事情,那么subtype能够表明接触事情的详细类型,例如单击、双击、长按等
  3. timestamp:表明事情产生的时刻戳,,单位是秒(s)
  4. modifierFlags:表明事情产生时键盘上的修饰键状况,如 Shift、Control、Option 等
  5. buttonMask:表明接触事情中的按下的按钮掩码。在接触事情中,用户可能会按下屏幕上的多个按钮,例如 Home 按钮、电源按钮等,buttonMask 特点能够表明这些按钮的状况
  6. allTouches:表明事情涉及到的一切接触目标,里面是一个由UITouch组成的列表

UIResponder

UIResponder 是 iOS 中呼应者目标的基类,它界说了一些办法和特点,用于呼应输入事情和接触事情,并将事情传递给后续的呼应者目标。 它包含以下特点:

iOS |关于触摸事件的传递机制以及响应流程

  1. nextResponder:下一个呼应者目标,也是一个UIResponder目标。在呼应事情的过程中,假如当时目标无法处理事情,体系会将该事情传递给 nextResponder 目标处理。假如 nextRespondernil,则表明当时目标已经是呼应链的末尾
  2. canBecomeFirstResponder:当时目标是否能成为第一呼应者,只读
  3. canResignFirstResponder:当时目标是否能够抛弃第一呼应者的身份,只读
  4. isFirstResponder:,当时目标是否是第一呼应者,只读

二、触屏事情的根本元素相关

介绍完触屏事情的根本元素的三个类,咱们来说一下它们的相关
   首先,在iOS使用程序中,事情一般是由UIApplication目标分发给UIResponder目标去处理的。当用户接触屏幕,产生触屏事情UIApplication目标会创立一个UIEvent目标(UITouch目标则是UIEvent目标中的一部分),然后将这个UIEvent目标发送给当时呼应事情的UIResponder目标。
  然后,假如当时呼应事情的UIResponder目标无法处理该事情,则会将事情传递给父视图或父控制器,知道有一个目标能成功处理该事情,否则,事情最终抵达回到了UIApplication目标则会被丢弃。
  最终,咱们能够经过重写UIResponder的父类办法来呼使用户事情。例如-touchesBegan:withEvent:办法,这个办法会在用户开端接触屏幕时被调用,咱们能够重写它,经过判别接触事情的方位,执行相应操作,比方弹出定制显示框。

三、触屏事情深入到到使用

  在 iOS 使用程序中,当咱们接触屏幕时,体系会将接触事情参加UIApplication目标的办理行列事情中,然后UIApplication目标会取出行列里最先进去的事情(FIFO),发出去处理,一般是传递给最上层的窗口目标(UIWindow 类),UIWindow 类经过 hitTest:withEvent: 办法来确认哪个视图目标(一同也是呼应者UIResponder),来负责处理该事情。因此,hitTest:withEvent: 办法是触屏事情和视图目标的要害联系点。
  hitTest:withEvent: UIView 类的办法,该办法会递归地遍历视图层次结构,找到最合适的视图目标(UIResponder)来处理接触事情,其寻觅规律如下图:

iOS |关于触摸事件的传递机制以及响应流程

上图是一幅依照数字从小到大增加进去的视图目标
举个例子:
1. 点击赤色view,寻觅次序是:
 白色view(找到,去子视图)-> 黄色view(找不到,去同级视图)-> 赤色view(找到,没有子视图,回来自己)
2. 点击蓝色view,寻觅次序是:
 白色view(找到,去子视图)-> 黄色view(找到,去子视图)-> 紫赤色view(找不到,去同级视图)-> 绿色view(找不到,去同级视图)-> 蓝色view(找到,没有子视图,回来自己)
3. 蓝色view躲藏,点击蓝色view的方位,寻觅次序是:
 白色view(找到,去子视图)-> 黄色view(找到,去子视图)-> 紫赤色view(找不到,去同级视图)-> 绿色view(找不到,去同级视图)-> 蓝色view(蓝色view躲藏了,回来nil,找不到,回来)->顺着呼应者链回到黄色view,然后回来黄色view


从现象能够分分出:

  • 调用次序是先从父视图逐级向其子视图遍历调用,假如视图在同级,就依照同级视图增加到这个父视图上的次序,从后向前遍历,即后增加的先遍历(FILO)
  • 每一个被遍历到的视图,会调用 -pointInside:withEvent: 办法判别点击事情是不是在本视图,假如不是,则回来 NO,就不会遍历其子视图。假如是,则回来 YES,就会遍历其子视图,先调用其子视图的 -hitTest:withEvent: 办法,然后该子视图又会调用-pointInside:withEvent: 办法判别点击事情是不是在本视图,如此递归下去。
  • 假如某个视图的 -hitTest:withEvent: 办法回来了呼应视图(呼应者),则会停止遍历还没遍历的视图。
  • 假如视图不接受交互userInteractionEnabled = NO;,或许设置了躲藏: hidden = YES;,或许透明度: alpha<=0.01 , 则不会呼应接触事情,会直接在-hitTest:withEvent: 办法回来nil,并不会调用-pointInside:withEvent: 办法

四、关于呼应流程

前面介绍了接触事情的传递过程,那么找到呼应者之后,呼应者是如何呼应事情的呢?
在 iOS 使用程序中,当-hitTest:withEvent: 办法回来了呼应视图,体系会将接触事情传递给该视图目标的touches办法来处理事情,它们别离是:

//接触事情的开端
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
//接触事情的移动
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
//接触事情的结束
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
//接触事情的撤销
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;

在上面四个办法中,touchesBegantouchesEnded表明接触事情的开端和结束,是一定会调用到的,至于移动和撤销需求依据手势和其他状况才会触发。touches办法来处理完事情后,体系会把接触事情UIEvent打包发送给呼应者的呼应办法,其流程如下图:

iOS |关于触摸事件的传递机制以及响应流程
留意:假如呼应者无法呼应事情,那么体系会顺着呼应者链从下往上找,直至找到最终的呼应者

五、总结

熟悉iOS接触事情传递的机制和流程,能够发明很多匪夷所思的功能,例如点击A控件,让B控件呼应事情,或许点击A控件,A控件以及A控件的父控件一同呼应事情。还需求留意的是,手势的辨认优先级是高于点击事情的,这方面的剖析等我找天有时刻再做个分享。