UITouchEvent 笔记

UITouchEvent 笔记
  • 如何确定点击事件由谁来响应
  • 如何中断响应链

确定响应者
chooseView.png

图释:

view 接收到 -hitTest 消息会通过自己调用 -pointInSize:withEvent: 来判断该点是不是在自己内部。下面以(Judge)来表示 view 通过该方法的判断结果。

触点1--A(Judge = YES)--B(Judge = NO)、D(Judge = NO)、E(Judge = NO)、F(Judge = NO)--A

触点2--A(Judge = YES)--B(Judge = YES)--C(Judge = YES)--C

触点3--A(Judge = YES)--B(Judge = NO)--E相对D在顶部,优先遍历E(Judge = YES)--E

触点4--不在A内--nil

归纳:
-hitTest: 会首先在 application 的 keyWindow 上调用(UIWindow 也是 UIView 的子类),并且该方法的返回值将被用来处理事件。会先判断产生触摸的 point 是否发生在自己的 bounds 内,如果没有将返回 nil;如果 point 在自己的范围内,则会为自己的每个子视图调用 -hitTest: 方法,只要有一个子视图通过这个方法返回一个 UIView 对象,那么整个方法就一层一层地往上返回;如果没有子视图返回 UIView 对象,则父视图将会把自己返回。

补充:
如果某个 view 的 enabled 或 userInteractionEnable 为 NO 或者 alpha<0.01 ,那么该view 的 -hitTest永远(-pointInSize:withEvent:返回YES/NO)都会返回nil,这意味着它和它的子视图没有机会去接收和处理事件。

在自定义控件时,我们经常要响应一个并非是矩形的区域,那么这时候,就可以通过重写 view 的-pointInSize:withEvent: 来限制响应区域了。

默认的写法:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {

    return CGRectContainsPoint(self.bounds, point);

}

现在想将范围限定在一个圆形内:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {

    BOOL inside = [self.superview pointInside:point withEvent:event];

    if (inside) {

    CGFloat radius = self.frame.size.width / 2;

    CGFloat dx = point.x - radius;

    CGFloat dy = point.y - radius;

    CGFloat distace = sqrt(dx * dx + dy * dy);

    return distace < radius;

    }

    return inside;

}

附(-hitTest:withEvent:的等效实现):

- (UIView *) hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    if (self.alpha <= 0.01 || !self.userInteractionEnabled || self.hidden) {

    return nil;

    }

    BOOL inside = [self pointInside:point withEvent:event];

    UIView *hitView = nil;

    if (inside) {

        NSEnumerator *enumerator = [self.subviews reverseObjectEnumerator];

        for (UIView *subview in enumerator) {

        if (hitView) {

            break;

        }

    }

    if (!hitView) {

        hitView = self;

    }

    return hitView;

    } 
    else {

        return nil;

    }

}
响应者链

寻找响应者是由下往上找,响应者处理事件则是由上往下处理。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;    

如果想要中断响应者链,只需在这些代理事件中不要调用对应的 super 就可以了。


史上最详细的iOS之事件的传递和响应机制-原理篇

转载于:https://www.cnblogs.com/imock/p/6687737.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值