iOS事件

作者: NapoleonY | 来源:发表于2018-06-14 16:29 被阅读16次

    概述

    iOS中事件有触摸事件、加速计事件、远程控制事件,下面以触摸事件为例研究下iOS事件相关的内容


    iOS事件分类

    UIResponsder

    iOS中继承了UIResponsder的对象才能够响应事件,如UIViewControllerUIViewUIApplication
    UIResponsder能够响应事件的原因是:提供了几个方法来处理事件

    //触摸事件
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;//手指触摸事件开始时调用该方法
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;//手指在屏幕上移动时调用该方法
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
    
    //加速计事件
    - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
    - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
    - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
    
    //远程控制事件
    - (void)remoteControlReceivedWithEvent:(UIEvent *)event;
    

    备注:

    1. 当多个手指同时触摸屏幕时,只会调用一次touchesBegan:withEvent:方法,touches中包含多个UITouch对象,分别对应着触摸屏幕的手指
    2. 如果是UIViewController的事件,在UIViewController中重写上面用到的方法即可;如果是UIView的事件,需要在子类中重写上面用到的方法

    实例:触摸屏幕,移动屏幕上的某个UIButton

    UIView的子类中重写touchesMoved: withEvent:方法

    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        UITouch *touch = [touches anyObject];
        CGPoint point = [touch locationInView:self];//当前点的位置
        CGPoint previousPoint = [touch previousLocationInView:self];//上一个点的位置
        CGFloat xPoint = point.x - previousPoint.x;
        CGFloat yPoint = point.y - previousPoint.y;
        NSLog(@"point:%@;previousPoint:%@;xPoint:%f;yPoint:%f",NSStringFromCGPoint(point), NSStringFromCGPoint(previousPoint), xPoint, yPoint);
        CGPoint centerPoint = self.btn.center;
        centerPoint = CGPointMake(centerPoint.x + xPoint, centerPoint.y + yPoint);
        self.btn.center = centerPoint;
    }
    

    iOS 事件处理过程

    iOS事件分为事件传递、事件响应两个过程。

    事件的产生

    发生触摸事件后,系统会将事件加入到由UIApplication管理的队列(先进先出FIFO),然后将队列最前面的事件分发下去:UIApplication->keyWindow->视图层次结构,找到合适的视图控件后,就会调用对应控件的事件方法(touchesBegan: withEvent:等)来处理对应的事件。

    事件的传递

    触摸事件的传递是从父控件传递到子控件

    • 寻找响应事件的控件步骤
      1. 首先判断keyWindow是否能响应事件
      2. 触摸点是否在自己身上
      3. 从后往前遍历子控件,重复前面的两个步骤(首先查找数组中最后一个元素)
      4. 如果没有符合条件的子控件,那就认为自己可以处理
    • UIView不能响应事件的三种情况
    1. 不允许交互userInteractionEnabled = NO
    2. 隐藏的控件不能接收事件
    3. 透明度:如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。

    事件传递实例

    注意:如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件

    事件传递实例

    查找符合条件的控件原理

    主要是通过以下两个控件实现查找

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;//返回nil,表明当前view以及子view没有能够响应事件的;如果不为nil,则表明当前view中有能响应事件的
    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;//返回YES,表明触摸点在当前view中
    

    通过调用hitTest:withEvent:可以判断是否有能够响应事件的控件,具体步骤为:
    产生触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回合适的view->[子控件 hitTest:withEvent:]->返回合适的view
    不过子控件是否能够响应事件,父控件都会把事件传递给子控件,如果子控件不能响应事件,则父控件响应事件

    实例:view中的button响应事件

    参考iOS超出父视图后点击事件不响应,文中想要view中的button响应点击事件,因此重写了hitTest:withEvent:方法

    响应者链

    在iOS程序中无论是最后面的UIWindow还是最前面的某个按钮,它们的摆放是有前后关系的,一个控件可以放到另一个控件上面或下面,那么用户点击某个控件时是触发上面的控件还是下面的控件呢,这种先后关系构成一个链条就叫“响应者链”。

    事件响应过程
    • 如果当前控件无法响应事件,就将事件按照视图层级结构(最上层是根视图)向上传递。如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递给控制器;如果当前view不是控制器的view,那么父视图就是当前view的上一个响应者,事件就传递给它的父视图
    • 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
    • 如果window对象也不处理,则其将事件或消息传递给UIApplication对象
    • 如果UIApplication也不能处理该事件或消息,则将其丢弃

    总结

    1. 触摸屏幕产生触摸事件后,触摸事件会被添加到由UIApplication管理的事件队列中
    2. UIApplication会从事件队列中取出最前面的事件,把事件传递给keyWindow
    3. keyWindow会在视图层次结构中找到一个最合适的视图来处理触摸事件
    4. 最合适的view会调用自己的touches方法处理事件,如果不能处理事件,就将事件沿着响应者链向上抛

    参考

    1. iOS事件传递->处理->响应
    2. iOS超出父视图后点击事件不响应

    相关文章

      网友评论

          本文标题:iOS事件

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