响应链及其事件传递

触摸事件处理的详细过程:

当用户点击屏幕后产生一个触摸事件,经过经过一系列的传递过程后,会找到最合适的视图控件来处理这个事件,找到最合适的视图之后,就会调用空间的touches那三个方法,这些方法的默认做法是把事件顺着响应者链条向上传递,将事件传递给上一个响应者进行处理。

传递过程

  1. UIApplication接收到事件,将事件传递给Window
  2. Window遍历subViewshitTest:withEvent:方法,找到点击区域内合适的视图来处理事件。
  3. UIView的子视图也会遍历其subViewshitTest:withEvent:方法,以此类推。
  4. 直到找到点击区域内,且处于最上方的视图,将视图逐步返回给UIApplication
  5. 在查找第一响应者的过程中,已经形成了一个响应者链。
  6. 应用程序会先调用第一响应者处理事件。
  7. 如果第一响应者不能处理事件,则调用其nextResponder方法,一直找响应者链中能处理该事件的对象。
  8. 最后到UIApplication后仍然没有能处理该事件的对象,则该事件被废弃。

怎么寻找最合适的view?用到以下的两个方法。

// 此方法返回的View是本次点击事件需要的最佳View
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

// 判断一个点是否落在范围内
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

事件传递给窗口或控件的后,就调用hitTest:withEvent:方法寻找更合适的view,如果子控件是合适的view,则在子控件再调用hitTest:withEvent:查看子控件是不是合适的view,一直遍历,直到找到最合适的view,或者废弃事件。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (self.alpha <= 0.01 || self.userInteractionEnabled == NO || self.hidden) {
        return nil;
    }
    
    BOOL inside = [self pointInside:point withEvent:event];
    if (inside) {
        NSArray *subViews = self.subviews;
        // 对子视图从上向下找
        for (NSInteger i = subViews.count - 1; i >= 0; i--) {
            UIView *subView = subViews[i];
            CGPoint insidePoint = [self convertPoint:point toView:subView];
            UIView *hitView = [subView hitTest:insidePoint withEvent:event];
            if (hitView) {
                return hitView;
            }
        }
        return self;
    }
    return nil;
}

总结:

     1、首先判断UIControl还是UIResponder;

     2、如果是UIResponder -(从上往下) 响应链找到最合适的视图  ;如果是 UIControl- UIApplication (如果类似view1有btn和tap 则响应btn,如果view1有btn,btn上有tap,则响应tap)

     3、有手势先手势,同级的话先看有没有UIControl。

tips:

1、手势不参与响应者链传递事件,但是也通过hitTest的方式查找响应的视图,手势和响应者链一样都需要通过hitTest方法来确定响应者链的。在UIApplication向响应者链派发消息时,只要响应者链中存在能够处理事件的手势,则手势响应事件,如果手势不在响应者链中则不能处理事件,处理最合适的view的响应。

2、如果同一视图有UIGesture和UIButton,会响应UIButton的响应事件;

3、如果同一视图添加多个UIGesture,只会响应最上面的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值