UI进阶第九发:iOS事件产生和传递过程(包括底层)

<一>事件产生和传递:


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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值