iOS-模拟响应者链,自己hittest方法

iOS-模拟响应者链,自己hittest方法

当用户触发的一个事件发生,UIKit会创建一个包含要处理的事件信息的事件对象。然后她会将事件对象放入active app’s(应用程序对象,每个程序对应唯一一个)事件队列。对于触摸事件,事件对象就是UIevent对象封装的一系列触摸集合。对于动作事件,这个事件对象依赖于使用的framework和你关心哪种动作事件。

事件通过特殊的路径传递直到被传递到一个可以处理该事件的对象。首先,单例的UIApplication对象从顶层的队列中获取事件,然后分发。典型的,它将事件发送到App的关键window(key window)对象,window则为了处理该事件而发送它到初始化对象(initial object),这个初始化对像依靠事件类型。

触摸事件(Touch events)。对于触摸事件,window对象首先会尝试将事件传递给事件发生的view。这个view就是所谓的hit-test view。寻找hit-test view的方法叫 hit-testing,具体描述可见“Hit-Testing Returns the View Where a Touch Occurred.”。

动作事件和远程控制事件(Motion and remote control events)。在这些事件中,window对象发送事件到第一个响应器。第一个响应器的描述见“The Responder Chain Is Made Up of Responder Objects.”。事件传递路径的最终目的时找出能处理和响应该事件的对象。因此,UIKit给适合处理该事件的对象发送事件。对于触摸事件,这个对象就是hit-test view,对于其他事件,这个对象就是第一个响应器(first responder)。

下面模拟实现hittest方法。

// hitTest:方法内部的参考实现
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    NSLog(@"%@----hitTest:", [self class]);

    // 如果控件不允许与用户交互那么返回 nil
    if (self.userInteractionEnabled == NO || self.alpha <= 0.01 || self.hidden == YES) {
        return nil;
    }

    // 如果这个点不在当前控件中那么返回 nil
    if (![self pointInside:point withEvent:event]) {
        return nil;
    }

    // 从后向前遍历每一个子控件

    for (int i = (int)self.subviews.count - 1; i >= 0; i--) {
        // 获取一个子控件
        UIView* lastVw = self.subviews[i];
        // 把当前触摸点坐标转换为相对于子控件的触摸点坐标
        CGPoint subPoint = [self convertPoint:point toView:lastVw];
        // 判断是否在子控件中找到了更合适的子控件
        UIView* nextVw = [lastVw hitTest:subPoint withEvent:event];
        // 如果找到了返回
        if (nextVw) {
            return nextVw;
        }
    }

    // 如果以上都没有执行 return, 那么返回自己(表示子控件中没有"更合适"的了)
    return self;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值