iOS 事件传递

24 篇文章 0 订阅
  1. 事件传递过程:
    UIApplication —> UIWindow —> UIWindow的子控件。
    从UIWindow开始,所有的UI控件会依据父子关系逐层寻找各自合适的View,最终找到一个最合适的view,将事件交给这个view处理。

  2. 合适的View的标准
    1) 能接收触摸事件。
    2)触摸点在自己身上。
    第2点很容易明白,但是第1点有点模糊,一个view怎样才能接收触摸事件呢,其实只要知道了不能接收事件的情况,剩下的就是能接收事件的情况了。
    满足以下3点之一,view不能接收事件:
    a. userInterfanceEnable = NO
    b. hidden = YES
    c. 0 < alpha <0.01

  3. 怎么找?
    从UIWidow开始,首先用2的标准判断自身是否是合适的View。
    如果不是,那么告诉父控件自己不是,父控件就是最合适的view(注意如果window不是合适的view,那么这个事件就会被废弃);
    如果是,这时它会去找最合适的View。会按添加顺序从后往前遍历自己的子控件(之所以要从后往前找,是出于性能的考虑,因为往往后加的视图是最有可能被点的),让子控件重复刚才的判断步骤,递归下去找到最合适的View。

  4. 代码实现
    刚才所说的都是文字描述,那么3所说的过程的代码表现是什么样的呢?
    当事件被传递到一个View上,系统会自动调用该View的以下方法:

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

在这个方法中做2的合适标准判断,并把最合适的View传递回去。我们往往可以重新该方法,自己指定View去处理事件。

  1. 模拟hitTest:withEvent:方法的实现
    在这个方法中我们知道它做了如下的事情:
    1) 判断能否接收触摸事件。
    2) 触摸点是否在自己的身上。
    3) 返回最合适的view。
    判断能否接收事件很容易,看代码
// 不能接收触摸事件
self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <=0.01

但是如何判断触摸点在自己身上呢?再介绍下面方法:

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

这方法返回YES就表示摸在了自己身上,返回NO表示没被摸到。(注意:这里的point表示的是调用者所在坐标系的点)

有了这些我们就可以自己实现事件的分发过程了:

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

    //  1. 判断自己能否接收触摸事件
    if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <=0.01) return nil;

    // 2. 判断触摸点是否在自己身上
    if (![self pointInside:point withEvent:event]) return nil;

    // 3. 找更合适的View
    // 从后往前遍历自己的子控件
    NSInteger count = self.subviews.count;

    for (NSInteger i = count; i >= 0; i--) {
        UIView *subView = self.subviews[i];

        // 转换坐标系
        CGPoint childPoint = [self convertPoint:point toView:subView];
        UIView *fitView = [subView hitTest:childPoint withEvent:event];

        //  如果fitView不为空,则说明找到了最合适的View
        if (fitView) {
            return fitView;
        }
    }

    // 来到这说明,没有找到更合适的View,那么自己就是最合适的view
    return self;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值