您的位置:首页 > 移动开发 > IOS开发

iOS 事件传递

2015-06-02 23:27 465 查看
事件传递过程:

UIApplication —> UIWindow —> UIWindow的子控件。

从UIWindow开始,所有的UI控件会依据父子关系逐层寻找各自合适的View,最终找到一个最合适的view,将事件交给这个view处理。

合适的View的标准

1) 能接收触摸事件。

2)触摸点在自己身上。

第2点很容易明白,但是第1点有点模糊,一个view怎样才能接收触摸事件呢,其实只要知道了不能接收事件的情况,剩下的就是能接收事件的情况了。

满足以下3点之一,view不能接收事件:

a. userInterfanceEnable = NO

b. hidden = YES

c. 0 < alpha <0.01

怎么找?

从UIWidow开始,首先用2的标准判断自身是否是合适的View。

如果不是,那么告诉父控件自己不是,父控件就是最合适的view(注意如果window不是合适的view,那么这个事件就会被废弃);

如果是,这时它会去找最合适的View。会按添加顺序从后往前遍历自己的子控件(之所以要从后往前找,是出于性能的考虑,因为往往后加的视图是最有可能被点的),让子控件重复刚才的判断步骤,递归下去找到最合适的View。

代码实现

刚才所说的都是文字描述,那么3所说的过程的代码表现是什么样的呢?

当事件被传递到一个View上,系统会自动调用该View的以下方法:

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


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

模拟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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: