63-iOS事件产生和传递过程(包括底层)

来源:互联网 发布:安徽网络教育报名时间 编辑:程序博客网 时间:2024/06/17 01:54
<一>事件产生和传递:

1>事件产生传递过程
发生触摸后-->UIApplition -->UIWindow(keyWindow,主窗口)-->窗口要找一个最合适的view

2>描述述事件产生传递过程

one:发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列
two:UIApplication会从事件队列中取出最前面的事件
       并将事件分发下去以便处理,通常先发送事件给应用程序的
主窗口(keyWindow)
three:主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件
four:找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理

3>如何寻找最合适的View
one:自己(窗口/View)是否能接收触摸事件?否,事件传递到此结束
two:触摸点是否在自己身上?否事件传递到此结束
three:如果满足前两个步骤,从后往前遍历子控件,重复前面的两个步骤,找出是否有比自己更合适的View.

注意: a>如果两个View在同一层级,那么按照向storyboard的拖拽前后顺序依次遍历.
         b>如果父控件不能接受触摸事件,那么子控件就不可能接收到触摸事件.

4>UIView不可接收触摸事件的三种情况
one:不接收用户交互 —> userInteractionEnabled = NO
two:隐藏 —> hidden = YES
three:透明 —> alpha = 0.0 ~ 0.01
透明时注意:
设置父控件的alpha,会影响到子控件的alpha(例如:设置父控件完全透明,它的子控件就会透明)

four:特殊情况
a.UIImageView的userInteractionEnabled默认就是NO
   因此UIImageView以及它的子控件默认是不能接收触摸事件的

b.解决:为了使UIImageView可以接收触摸事件
将UIImageView的userInteractionEnabled默认就是YES




<二>事件产生传递过程(底层):

发生触摸后-->UIApplition -->UIWindow(keyWindow,主窗口)-->窗口要找一个最合适的view

1.发生触摸后系统将该事件添加到UIApplition队列

2.UIApplition对象将事件发送给主窗口
    
UIWindow *keyWindow=[UIApplication sharedApplication].keyWindow;
    
1>判断窗口能否接收事件
    
2>判断点在不在窗口

3.从后向前遍历窗口的子控件,寻找最合适的View(使用hitTest方法)

hitTest方法
1.目的:寻找最合适的View
2.参数point:方法调用者坐标系上的点
3. 什么时候调用:当一个事件传递给另一个控件的时候就会调用
4.hitTest方法的用处:
one:返回系统默认方法return [super hitTest:point withEvent:event](具体怎么实现如下1,2,3,4,5); 
two:返回当前窗口指定的View return self.subviews[0]; 
three:返回当前Window处理return nil; 
four:返回当前viewreturn self; 
5>hitTest方法底层如何寻找到最适合的View的(1,2,3,4,5如下)

-(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;
    }
    
/*
     
pointInside方法
     
1>作用:判断这个点在不在方法调用者的坐标系上面
     
2>什么时候调用:系统的hitTest:withEvent方法默认会调用,判断当前点在不在方法调用者的控件上
     
3>point参数:就是方法调用者坐标系上的点
     */

    
    
//3.从后向前遍历当前控件的所有子控件(a,b,c)
    
int count=(int)self.subviews.count;
    
for (int i=count-1; i>=0; i--) {
        
        
//1>取出子控件
        
UIView *childView=self.subviews[i];
        
        
//2>转换坐标系,把当前控件的坐标系转换成子控件的坐标系 
        
CGPoint chidp=[self convertPoint:point toView:childView];
        
/*
        
convertPoint方法
        
作用:[A convertPoint:point toView:B]:将A的坐标系转换为B的坐标系
        */

        
//3>让子控件去寻找做合适的view
        
UIView *fitView=[childView hitTest:chidp withEvent:event];
       
        
//4>遍历的时候找到最合适的View,就返回
        
if (fitView) {
            
return fitView;
        }
    }
    
//5>遍历当前控件的子控件没有找到最适合的View,那么当前控件就是最适合的View,直接返回自身
    
return self;
}
0 0