一、事件传递机制
在iOS中,只有继承于UIResponder的子类,才可以处理事件。
1.当iOS程序中发生触摸事件后,系统会将事件加入到UIApplication管理的一个任务队列中
2.UIApplication将处于任务队列最前端的事件向下分发。即UIWindow。
3.UIWindow将事件向下分发,即UIView。
4.UIView首先看自己是否能处理事件,触摸点是否在自己身上。如果能,那么继续寻找子视图。
5.遍历子控件,重复3,4两步。如果没有在子控件找到触摸点,那么自己就是事件处理者。
6.如果自己不能处理触摸响应,那么不做任何处理。
事件分发传递,以下三种情况是不做处理的:
1.alpha < 0.01
2.userInteractionEnabled = NO
3.hidden = YES
若父视图事件不做处理,(以上三种情况),那么子视图也不会传递事件,改事件传递被废弃。
//此方法返回的view是本次点击事件需要的最佳view
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
//判断一个点是否在视图范围内
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
1.通过重写hitTest方法,可将点击的点移动到子view。
2.重写pointInside方法,可扩大按钮的点击区域。
eg: 按钮的点击区域重写,小于44*44做处理,大于不处理
下面示例是定义一个button的可点击区域
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
CGRect bounds = self.bounds;
CGFloat widthDelta = MAX(44 - bounds.size.width, 0);
CGFloat heightDelta = MAX(44 - bounds.size.height, 0);
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
return CGRectContainsPoint(bounds, point);
}
二、事件响应链
1.事件响应链的响应刚好和事件传递相反,事件传递是从UIApplication管理起点,逐级向下传递。而响应链则从下向上传递。响应链是通过nextResponder属性组成的一个链表,点击的view有 superView,nextResponder就是superView;
image.png
最有机会处理事件的就是通过事件传递找到的 first responder,如果没有进行处理,就会沿着事件响应链传递给下一个响应者 nextResponder,一直追溯到最上层 UIApplication。若都没有进行处理,就丢弃事件。
处理事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
对于触摸事件,系统提供了上面四种方法来处理。如果重写了上述方法,那么事件就会在此中断,并且不再沿着事件响应链进行传递;如果需要继续进行传递,则需要调用 super 方法。
网友评论