关于响应链的一些研究成果#

关于响应链的一些研究成果#

假设我们有一个VC1,VC1上面加盖一个View0 和 View1,点击VC跳转进VC2; 现在的需求是:点击View0不跳转,但是点击View1跳转

1、在View0的子类实现如下方法即可:

//hitTest:withEvent: 和 touchesBegan:withEvent:混用,可以实现强行阻断点击事件的响应链
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    if (CGRectContainsPoint(self.frame, point)) {
        return self;
    }else{
        return nil;
    }
}
//如果不进行混用,也就是说只实现hitTest:withEvent:而不实现touchesBegan:withEvent:无效
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSLog(@"");
}

2、如果需要截断View1的事件响应,那么在View1里面实现

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSLog(@"");
}

以上代码亲测有效

科普在前

1、首先产生了事件之后,系统会把事件打包成event,交给application,然后传递给window,从大到小的锁定,锁定是哪个view产生的事件,这一条链就是通过hitTest
2、锁定了之后,就看这个view能否响应,如果不能,就按照之前的那条链往上询问,能否响应就是走的touchBegin
3、手势本质来讲就是对touch的封装,但是默认情况下手势会禁止touchBegin的响应
4、如果要打开,手势有一个属性,BOOL类型,可以让手势和touch的那一套方法共存

子视图超出父视图的解决方案 :在父视图里面写

-(UIView *)hitTest:(CGPoint)point
         withEvent:(UIEvent *)event{
    UIView *view = [super hitTest:point
                        withEvent:event];
    if (!view) {
        //将坐标由当前视图发送到 指定视图 fromView是无法响应的范围小父视图
        CGPoint stationPoint = [self.delBtn convertPoint:point
                                                fromView:self];
        if (CGRectContainsPoint(self.delBtn.bounds, stationPoint)){
            view = self.delBtn;
        }
    }return view;
}