美文网首页
iOS Touch以及事件响应链(一)hit-testing

iOS Touch以及事件响应链(一)hit-testing

作者: ashura_ | 来源:发表于2017-04-30 22:18 被阅读0次

    简介

    本文的目的是让读者彻底了解,iOS系统是如何识别Touch事件,以及如何传递对应的事件到指定的View

    iOS事件主要分为四种

    1. touch事件
    2. 运动事件
    3. 远程事件
    4. 按压事件
      参见UIEventtype属性
    typedef NS_ENUM(NSInteger, UIEventType) {
        UIEventTypeTouches,
        UIEventTypeMotion,
        UIEventTypeRemoteControl,
        UIEventTypePresses NS_ENUM_AVAILABLE_IOS(9_0),
    };
    
    1480993244519.png

    这里只介绍第一种Touch事件

    为了便于区分把TouchEvent
    touchesBegan:withEvent:叫做Touch,手势类型的叫Gesture.

    TouchEvent.png

    事件处理流程

    1. App(DemoTSAplication类,UIApplication子类,代表当前应用)先通过hit-testing找到touch View.
    2. 而后APP收到sendEvent:事件,传递给Window(TSWindow)的sendEvent:,由TSWindow分解成touchesBegan:withEvent:touchesMoved:withEvent,touchesEnd:withEvent,touchesCancel:withEvent等事件。
    3. 具体的手势识别以及Target-ActionTSWindowsendEvent:收到Touch Event状态的UITouchPhaseBeganUITouchPhaseEnded|UITouchPhaseCancelled之间进行。
      截屏2016_12_8_上午9_51.png

      当前controller叫hit-testing,controller对应的view叫AView,AView第一个子View叫BView,BView有一个唯一子ViewCView,AView第二个子View叫DView,DView没有子View。以此界面,来分析hit-testing

      点击AView

      时序图

      SequenceDiagram2.jpg

      时序图的步骤在一次touch调用了2遍,看日志,原因未知,没有查到资料。

      日志

      2016-12-08 11:00:07.546 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] Before
      2016-12-08 11:00:07.547 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] Before
      2016-12-08 11:00:07.547 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] After
      2016-12-08 11:00:07.547 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] Before
      2016-12-08 11:00:07.548 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] Before
      2016-12-08 11:00:07.548 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] After
      2016-12-08 11:00:07.548 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] Before
      2016-12-08 11:00:07.548 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] Before
      2016-12-08 11:00:07.549 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] After
      2016-12-08 11:00:07.549 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] After
      2016-12-08 11:00:07.549 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:BView] Before
      2016-12-08 11:00:07.549 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:BView] Before
      2016-12-08 11:00:07.550 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:BView] After
      2016-12-08 11:00:07.550 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:BView] After
      2016-12-08 11:00:07.550 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] After
      2016-12-08 11:00:07.551 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] After
      2016-12-08 11:00:07.551 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] Before
      2016-12-08 11:00:07.551 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] Before
      2016-12-08 11:00:07.551 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] After
      2016-12-08 11:00:07.552 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] Before
      2016-12-08 11:00:07.552 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] Before
      2016-12-08 11:00:07.552 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] After
      2016-12-08 11:00:07.552 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] Before
      2016-12-08 11:00:07.553 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] Before
      2016-12-08 11:00:07.553 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] After
      2016-12-08 11:00:07.553 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] After
      2016-12-08 11:00:07.553 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:BView] Before
      2016-12-08 11:00:07.553 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:BView] Before
      2016-12-08 11:00:07.554 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:BView] After
      2016-12-08 11:00:07.554 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:BView] After
      2016-12-08 11:00:07.554 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] After
      2016-12-08 11:00:07.554 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] After
      

      第一遍调试堆栈

      ![TSWindow_m1.png](https://img.haomeiwen.com/i3134371/057baa6e9a3c9e17.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

      第二遍调试堆栈

      解析:

      1. 第一个收到hitTest:withEvent:肯定是TSWindow,TSWindow调用pointInside:withEvent:返回YES,代表点击在TSWindows上,倒序递归遍历TSWindowsubviews。
      2. 只有一个子ViewAView,调用AViewpointInside:withEvent:返回YES,倒序递归遍历AViewsubviews.
      3. 先遍历DView,调用DViewpointInside:withEvent:返回NO,DViewhitTest:withEvent:返回nil。
      4. 再遍历BView,,调用BViewpointInside:withEvent:返回NO,BViewhitTest:withEvent:返回nil。
      5. AView所有子View都返回nil了,就返回self.
      点击DView

      时序图

      SequenceDiagram3.jpg

      日志

      2016-12-08 14:30:34.886 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] Before
      2016-12-08 14:30:34.886 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] Before
      2016-12-08 14:30:34.886 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] After
      2016-12-08 14:30:34.887 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] Before
      2016-12-08 14:30:34.887 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] Before
      2016-12-08 14:30:34.888 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] After
      2016-12-08 14:30:34.888 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] Before
      2016-12-08 14:30:34.888 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] Before
      2016-12-08 14:30:34.888 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] After
      2016-12-08 14:30:34.889 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] After
      2016-12-08 14:30:34.889 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] After
      2016-12-08 14:30:34.889 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] After
      2016-12-08 14:30:34.890 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] Before
      2016-12-08 14:30:34.890 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] Before
      2016-12-08 14:30:34.890 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] After
      2016-12-08 14:30:34.890 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] Before
      2016-12-08 14:30:34.891 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] Before
      2016-12-08 14:30:34.891 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] After
      2016-12-08 14:30:34.891 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] Before
      2016-12-08 14:30:34.891 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] Before
      2016-12-08 14:30:34.892 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] After
      2016-12-08 14:30:34.892 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] After
      2016-12-08 14:30:34.892 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] After
      2016-12-08 14:30:34.892 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] After
      
      点击BView

      时序图

      SequenceDiagram4.jpg
      日志
      2016-12-08 15:19:16.611 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] Before
      2016-12-08 15:19:16.612 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] Before
      2016-12-08 15:19:16.612 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] After
      2016-12-08 15:19:16.613 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] Before
      2016-12-08 15:19:16.614 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] Before
      2016-12-08 15:19:16.614 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] After
      2016-12-08 15:19:16.615 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] Before
      2016-12-08 15:19:16.615 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] Before
      2016-12-08 15:19:16.616 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] After
      2016-12-08 15:19:16.616 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] After
      2016-12-08 15:19:16.617 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:BView] Before
      2016-12-08 15:19:16.617 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:BView] Before
      2016-12-08 15:19:16.617 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:BView] After
      2016-12-08 15:19:16.618 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:CView] Before
      2016-12-08 15:19:16.618 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:CView] Before
      2016-12-08 15:19:16.619 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:CView] After
      2016-12-08 15:19:16.619 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:CView] After
      2016-12-08 15:19:16.620 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:BView] After
      2016-12-08 15:19:16.620 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] After
      2016-12-08 15:19:16.621 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] After
      2016-12-08 15:19:16.621 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] Before
      2016-12-08 15:19:16.622 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] Before
      2016-12-08 15:19:16.622 TSEventDemo[35550:1352018] -[TSWindow pointInside:withEvent:] After
      2016-12-08 15:19:16.623 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] Before
      2016-12-08 15:19:16.623 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] Before
      2016-12-08 15:19:16.623 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:AView(MainView)] After
      2016-12-08 15:19:16.624 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] Before
      2016-12-08 15:19:16.624 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] Before
      2016-12-08 15:19:16.625 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:DView] After
      2016-12-08 15:19:16.625 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:DView] After
      2016-12-08 15:19:16.625 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:BView] Before
      2016-12-08 15:19:16.625 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:BView] Before
      2016-12-08 15:19:16.626 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:BView] After
      2016-12-08 15:19:16.626 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:CView] Before
      2016-12-08 15:19:16.626 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:CView] Before
      2016-12-08 15:19:16.627 TSEventDemo[35550:1352018] -[TSView pointInside:withEvent:] [name:CView] After
      2016-12-08 15:19:16.627 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:CView] After
      2016-12-08 15:19:16.628 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:BView] After
      2016-12-08 15:19:16.628 TSEventDemo[35550:1352018] -[TSView hitTest:withEvent:] [name:AView(MainView)] After
      2016-12-08 15:19:16.628 TSEventDemo[35550:1352018] -[TSWindow hitTest:withEvent:] After
      

      解析
      不再解析,总结成一句话:

      倒序递归subview,直到某个子ViewpointInside:withEvent:返回YES,没有subview或者subviews的hitTest:withEvent:返回nil,则返回self.

      点击CView

      用提供的Demo,自验看日志,即可。

      模拟代码

      发现用文字流程图对程序员来说,还没代码更直观。故附上模拟代码

      伪代码

      - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
      {
          if (self.hidden || !self.userInteractionEnabled || self.alpha < 0.01 || ![self pointInside:point withEvent:event] || ![self _isAnimatedUserInteractionEnabled]) {
              return nil;
          } else {
              for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
                  UIView *hitView = [subview hitTest:[subview convertPoint:point fromView:self] withEvent:event];
                  if (hitView) {
                      return hitView;
                  }
              }
              return self;
          }
      }
      

      Demo代码

      放在第二篇

    相关文章

      网友评论

          本文标题:iOS Touch以及事件响应链(一)hit-testing

          本文链接:https://www.haomeiwen.com/subject/euoxtxtx.html