您的位置:首页 > 产品设计 > UI/UE

iOS UI高级之事件的分发

2015-08-16 10:23 253 查看
一、 事件的分发

1、当点击屏幕的时候iOS设备的硬件会检测(检测的原理可以去查找资料,好像触摸屏分为电容屏和电阻屏,然后根据一些他们的特性来检测的)到这个触摸事件,然后打包到UIEvent对象防盗应用程序的事件分发队列里面(队列:先进先出的特点,所有先进去的先执行)。UIApplication对象从队列里面取出最先进去的那个事件然后进行分发。一般会先传递给Window 。

解释下这两个方法:

方法1

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

方法2

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

当系统在调用第一个方法时会自动调用第二个方法,可以看出,第二个方法是判断point那个点是不是在调用第一个方法的视图上,如果是则方法1会返回当前这个视图,否则返回nil。事件的处理是根据返回的视图来执行响应的处理方法的,等下讲解关于事件链的传递,现在先讲事件的分发。

来看看实例:UIWindow->myview->view1、view2

在window上面有一个子视图myview,在my view视图上有两个子视图view1,view2

假如说我们点击了view2视图。



分析点击view2之后事件的分发流程:

在点击了view2之后 系统检测到这个事件,然后放在了事件的队列里面,当uiapplication对象取出事件的时候向window发送消息,此时会调用window里面的

(UIView *)hitTest:(CGPoint)point
withEvent:(UIEvent *)event 方法 ( 编号:方法1)

在调用此方法的时候会在方法里面调用- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 方法
(编号: 方法2)

当方法2判断出point(触摸屏幕的手指的位置)这个点在window上面 ,则会向直接加载到window上的视图myiew发送消息,同时执行过程和上面一样。先调用方法1.同时在方法1里面调用方法2,检测到point那个点是在myview上,则会向所有的子视图也就是view1和view2发送消息,然后执行相同的操作。

注意:在向所有的子视图发送消息的时候会先给top层那个发送(每个视图上的子视图的存放都是放在数组里面的,先添加进去的下标小,后添加的大)。因为,假如有多个视图是重合在一起的情况,检测到的点肯定都是在这些重合的视图上的,但是返回那个视图呢?一般我们只处理顶层那个我们看的到到视图的响应,这个顶层点视图肯定是最后添加上去的,所有在向所有的子视图发送消息时会先发送给顶层那个,这样假如有重合的情况下 在重叠的下面视图就不必发送消息了,这样效率会高。 我们也可以自定义方法1
来返回指定的视图。

例如:在一个视图view上有一个button和一个scrollview重叠,button在下面,scrollview在顶层。我们触摸这个位置的时候方法1默认返回的是视图scrollview,但是我们可以自定义让它返回button视图

我们在view这个视图点implement里面重写方法1:

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



//事件拦截 如果view有这些条件限制 则返回nill

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

return nil;
}
//判读触摸点是不是在这个视图里面 如果是 则遍历子视图 button和scrollview 系统默认的是先向top层的发送消息,然后返回它,这里我们判断出这个点在重叠的区域的时候让它返回button

if ([self
pointInside:point
withEvent:event]) {

NSArray *subViews =
self.subviews;

//从顶层开始遍历
因为如果有重叠的 情况
一般在下面层的 控件事件我们
不需要处理 只处理顶层那个

for (NSInteger i = subViews.count -
1; i >= 0; i--) {

UIView *view = subViews[i]; //第一次循环的时候 view = scrollview

//
将触摸点转化到scrollview 视图上

CGPoint convertPoint = [self
convertPoint:point
toView:view];
//这句比较关键 在重叠的情况下 系统默认的返回时top层那个视图
这里也就是scrollview

UIView *view1 = [view
hitTest:convertPoint withEvent:event];

return view1;//系统估计在这里就直接返回top视图了 但是我们要返回的不是这个 因此下面我们改变返回的视图

if (view1 != nil) {

return subviews[i-1];//返回button
break;
}



else

return nill;



这里我们 的事件的分发就讲完了,实际上就是不断的查找,直到找到触摸的那个视图。

关于响应者链欢迎点击下一篇博客(由于篇幅的原因写在下一篇)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: