响应者链条!!!看我的

2018-04-07  本文已影响0人  我是繁星

比较官方的解释:

用户事件发生的时候,UIKit会创建一个事件对象Event Object,该对象包含事件处理所必须的一些信息。然后会将事件对象置于激活的app事件队列。例如触摸事件就是对象一系列触摸信息的包装集。
包含两个过程

说说理解:

整个过程分为两部分(查找相应者)和(响应者处理),并且是由responder连接起来的,也就是响应链名字的由来
查找响应者:从UIWindow开始,顺着视图树查找到目标响应者。
响应者处理:touches方法由原路下发。
手势也是通过响应链处理的,但是手势可以阻断父视图touches方法。的传播。

Demo:

image.png

首先创建redView、blueView继承自UIView,一白一红,分别在hitTest、pointInside和touchesBegan中添加打印。
1.redView加到self.view上,blueView加到redView上。
2.redView和blueView都加到self.view上覆盖。
3.redView加到self.view上,blueView加到redView上,redView isUserInteractionEnabled = false。
4.redView和blueView都加到self.view上覆盖,redView isUserInteractionEnabled = false。
依次打印结果如下:


image.png image.png image.png image.png image.png

对比1、4 redView的isUserInteractionEnabled = false ,所以对应view的hitTest返回nil。其所有子视图都无法接收事件了(所以加到UIImageView上的视图默认是都接收不到事件的)。

对比2、4 redView的isUserInteractionEnabled = false,blueView还可以接收事件,因为是redView和blueView无父子视图的关系,所以同级时redView不接收事件与blueView无关。

对比1、2 当redView和blueView同时加到self.view上的时候时,且有重合区域,后加到self.view上的在上面(默认,可调换),优先接收事件。

总结:

当有触摸行为发生后会从UIWindow开始调用hitTest-> pointInside判断是否在范围内,如果在的话依次调用其子视图的hitTest-> pointInside判断是否在其子视图范围内,如果子视图有重叠则显示在上面的响应,找到目标View(响应手势的View),touchesBegin等方法会回调,且依次执行父视图的touchesBegin等方法(注意这里父视图的手势并不能响应)。

Demo:https://github.com/starFanX/-Demo

最后再说说手势和UIButton

不知道大家有没有发现UIButton的父视图是无法响应touches方法的,原因当然是UIButton阻断了响应链,如果想继续传递的话可以重写button,直接调用他的nextRespond的touches方法、3个都要写。

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.next?.touchesBegan(touches, with: event)
    }

关于UIGestureRecognizer,大家用的时候回发现,如果不做特殊处理的话,多个重叠的view都添加了手势,只会响应命中view添加的手势,且手势并不会阻断响应者链条,其实我们可以通过一系列UIGestureRecognizerDelegate去控制手势的响应
例如:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool 
//标识相同类型的手势都会得到响应。
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
//判断收到的手势是否响应。可以通过
上一篇下一篇

猜你喜欢

热点阅读