美文网首页
手势与响应链

手势与响应链

作者: 智能音响 | 来源:发表于2019-08-10 13:32 被阅读0次

    写了一个简单Demo,需要通过控制台查看打印信息。

    响应链

    响应链

    这张图是用来说明响应链如何工作的。在HitTest已经找到最适合视图的前提下,事件从最顶部(UILabel/UITextField/UIButton)沿着实线传递。事件被处理,停止传递。整个链中都没有处理,作为无效事件被舍弃。

    HitTest

    当系统检查到手指触摸屏幕时,会把触摸事件加到UIApplication的事件队列中,UIApplication从事件队列中取出最新的触摸事件进行分发传递到UIWindow进行处理。 UIWindow会通过hitTest:withEvent:方法寻找触碰点所在的视图,这个过程称之为hit-test view

    hit-test用来确定响应者(UIResponder)。可以简单理解为获取到响应区域的最顶层(最后添加)的可以响应的视图

    hitTest方法忽略以下的视图:

    1. 透明度小于0.01 alpha < 0.01

    2. 视图是隐藏的 hidden=YES

    3. 用户交互关闭的 userInteractionEnabled = NO

    HitTest与响应链如何合作

    HitTest找到响应者(UIResponder)后,UIApplication会把事件传递给响应者,触发响应链。

    #0 0x000000010153990d in -[TouchView2 touchesBegan:withEvent:] 

    #1 0x0000000105634240 in -[UIWindow _sendTouchesForEvent:] ()

    #2 0x0000000105635bca in -[UIWindow sendEvent:] ()

    #3 0x000000010561430e in -[UIApplication sendEvent:] ()

    手势与HitTest

    当视图上添加手势时,手势的优先级高于响应链。

    当我没搞明白手势的优先级时,我有个疑惑,手势的高优先级,只影响响应链还是在hitTest时就产生作用了?

    还猜测hitTest碰到手势是不是直接触发手势处理方法,都不在往下传递了。Demo中第一个例子就是为了验证这个问题。从实际处理过程看,手势不影响hitTest.

    ps: hitTest会被触发两次。网上搜索这个问题,更低版本都iOS会调用3次,原因未知。

    手势与响应链

    既然手势不影响hitTest,只验证响应链相关都问题就好。

    我验证都过程,完全是试错的过程,没有前后逻辑,直接放出结论。

    1. 手势有自己单独的处理逻辑,不是依附在响应链上的。不要把手势作为响应链的角色。

    2. 手势优先级高。手势识别成功会取消响应链处理。响应链即使第一时间处理事件,也无法反向取消手势处理过程。

    3. UIApplication把点击事件转发响应者时,同时也转发给手势。

    [UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:]

    这里补充我之前的错误想法:响应链传递过程中,判断当前视图有没有手势,有手势先触发手势识别,然后在调用默认touchesBegan方法。这个观点认为子视图处理完事件,父视图的手势不会被触发。与第二条结论冲突。

    4. 响应点击的视图,如果既有手势也实现了touchesBegan,两个都会被触发。touches的其他方法会在手势识别后取消。在手势点击事件和touchesBegan中对参数做累加,看到看到每次点击加2.

    5. 子视图父视图都有手势时,能从UITouch中获取到手势数组。手势是同时识别的,不是等到上一个手势识别完才识别下一个。数组前面的手势比后面的早识别一点时间。子视图的手势比父视图手势靠前。某一个手势识别成功,其他手势识别过程会被取消。

    6. UIControl和手势叠加时,响应的是UIControl,因为UIApplication分发时,直接分发给了UIControl而不是手势。打印一下调用堆栈就能明白。没有写这个demo。

    Demo介绍

    第二个例子是关于手势和响应链冲突的。touchview1-touchview4 共4个视图。

    TouchView1 红色,有手势

    TouchView2 绿色,有手势

    TouchView3 灰色,无手势

    TouchView4 蓝色 ,无手势

    一个视图在另一个内部,即为子视图。

    验证结论1,2, 点击灰色视图。灰色视图实现了touchesBegan方法,父视图的手势还是被识别了。

    验证结论3,4,点击灰色视图。number每次+2.

    验证结论5,点击绿色视图。可以从log中看到gestureRecognizerShouldBegan调用时间不同。

    蓝色视图,不包含手势的响应链传递。

    相关文章

      网友评论

          本文标题:手势与响应链

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