继承关系
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这样就达到了扩大子视图响应范围的效果
如上图,在橙色的图上点击,由于蓝色是第一层子视图,所以蓝色会被事件传递一次,调用了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和手势同时存在,则会按照响应链,先响应单击事件