iOS响应链和手势总结

继承关系

image.png

UIResponder 继承关系图
只有继承了UIResponder的对象才能接受并处理事件

事件传递

UIView是UIResponder的子类,可以覆盖下列4个方法处理不同的触摸事件

// 一根或者多根手指开始触摸view,系统会自动调用view的下面方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
// 一根或者多根手指在view上移动,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
// 一根或者多根手指离开view,系统会自动调用view的下面方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
// 触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用view的下面方法
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
// 提示:touches中存放的都是UITouch对象

触摸事件的传递是从父控件传递到子控件,遍历子视图的时候从后到前
也就是UIApplication->window->寻找处理事件最合适的view

判断条件是

  • 1.自身是否能够响应触摸事件
  • 2.触摸点在不在自己身上
  • 3.1 如果在则遍历子视图,寻找最合适的
  • 3.2 如果没有子视图,且找不到最合适的,则自身成为最合适的响应者
    然后该类响应touchs方法

事件拦截

如果触摸点不在自身上则不去遍历子视图
如果在则一定会去遍历所有子视图,所以说不管子视图有没有这个点,只要父视图有,则会默认被遍历一遍。
第一层的子视图都会调用hitTest:withEvent:方法

所以只要在hitTest:withEvent:中返回哪个View,哪个View就是响应者。
例如:点击父视图,子视图重写hitTest:withEvent:,返回self这样就达到了扩大子视图响应范围的效果

image.png

如上图,在橙色的图上点击,由于蓝色是第一层子视图,所以蓝色会被事件传递一次,调用了hitTest
在蓝色类C中创建一个手势方法,并重写hitTest返回self,这样就能响应了

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(aviewAction)];
        [self addGestureRecognizer:tap];
    }
    return self;
}

- (void)cviewAction {
    NSLog(@"单击传递到C");
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    return self ;
}

hit:withEvent:方法底层会调用pointInside:withEvent:方法判断点在不在方法调用者的坐标系上。因为重写了,所以pointInside就没调用了。
pointInside:withEvent:方法判断点在不在当前view上(方法调用者的坐标系上)如果返回YES,代表点在方法调用者的坐标系上;返回NO代表点不在方法调用者的坐标系上,那么方法调用者也就不能处理事件。

事件的传递和响应的区别:
事件的传递是从上到下(父控件到子控件),事件的响应是从下到上(顺着响应者链条向上传递:子控件到父控件。

手势相关

1.如果一个手势A的识别部分是另一个手势B的子部分时,默认情况下A就会先识别,B就无法识别

- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;

2.使多个手势同时生效

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

3.父视图和子视图都有手势的时候,子视图会出现无法响应的情况

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isKindOfClass:[UITableView class]]) {
        return NO;
    }
    
    if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]) {
        return NO;
    }
    
    return YES;
}

4.UIControl和手势同时存在,则会按照响应链,先响应单击事件

你可能感兴趣的:(iOS响应链和手势总结)