美文网首页知识点合集
事件的传递和响应机制

事件的传递和响应机制

作者: 周二可 | 来源:发表于2018-04-08 11:31 被阅读5次

    事件的产生

    • 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中,为什么是队列而不是栈?因为队列的特点是FIFO,即先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列。
    • UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。
    • 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。
    • 找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。

    事件的传递

    • 触摸事件的传递是从父控件传递到子控件
    • 也就是UIApplication->window->寻找处理事件最合适的view

    如何寻找最合适的view

    应用如何找到最合适的控件来处理事件?
    1.首先判断主窗口(keyWindow)自己是否能接受触摸事件
    2.触摸点是否在自己身上
    3.从后往前遍历子控件,重复前面的两个步骤(首先查找数组中最后一个元素)
    4.如果没有符合条件的子控件,那么就认为自己最合适处理

    详述:
    1.主窗口接收到应用程序传递过来的事件后,首先判断自己能否接手触摸事件。如果能,那么在判断触摸点在不在窗口自己身上
    2.如果触摸点也在窗口身上,那么窗口会从后往前遍历自己的子控件(遍历自己的子控件只是为了寻找出来最合适的view)
    3.遍历到每一个子控件后,又会重复上面的两个步骤(传递事件给子控件,1.判断子控件能否接受事件,2.点在不在子控件上)
    4.如此循环遍历子控件,直到找到最合适的view,如果没有更合适的子控件,那么自己就成为最合适的view。
    找到最合适的view后,就会调用该view的touches方法处理具体的事件。所以,只有找到最合适的view,把事件传递给最合适的view后,才会调用touches方法进行接下来的事件处理。找不到最合适的view,就不会调用touches方法进行事件处理。
    注意:之所以会采取从后往前遍历子控件的方式寻找最合适的view只是为了做一些循环优化。因为相比较之下,后添加的view在上面,降低循环次数。

    事件的响应

    响应者链的事件传递过程:

    1、如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递给控制器;如果当前view不是控制器的view,那么父视图就是当前view的上一个响应者,事件就传递给它的父视图
    2、在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
    3、如果window对象也不处理,则其将事件或消息传递给UIApplication对象
    4、如果UIApplication也不能处理该事件或消息,则将其丢弃

    hitTest:withEvent的实现

    // 什么时候调用:只要事件一传递给一个控件,那么这个控件就会调用自己的这个方法
    // 作用:寻找并返回最合适的view
    // UIApplication -> [UIWindow hitTest:withEvent:]寻找最合适的view告诉系统
    // point:当前手指触摸的点
    // 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] == NO) return nil; 
        // 3.从后往前遍历子控件数组 
        int count = (int)self.subviews.count; 
        for (int i = count - 1; i >= 0; i--)     { 
        // 获取子控件
        UIView *childView = self.subviews[i]; 
        // 坐标系的转换,把窗口上的点转换为子控件上的点 
        // 把自己控件上的点转换成子控件上的点 
        CGPoint childP = [self convertPoint:point toView:childView]; 
        UIView *fitView = [childView hitTest:childP withEvent:event]; 
        if (fitView) {
        // 如果能找到最合适的view 
        return fitView; 
        }
        } 
        // 4.没有找到更合适的view,也就是没有比自己更合适的view 
        return self;
        }
        // 作用:判断下传入过来的点在不在方法调用者的坐标系上
        // point:是方法调用者坐标系上的点
        //- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
        //{
        // return NO;
        //}
        - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 
        NSLog(@"%s",__func__);
        }
    
    
    

    https://www.jianshu.com/p/2e074db792ba

    相关文章

      网友评论

        本文标题:事件的传递和响应机制

        本文链接:https://www.haomeiwen.com/subject/bcmbqftx.html