美文网首页
iOS 事件机制

iOS 事件机制

作者: WesleyLien | 来源:发表于2017-02-23 00:28 被阅读0次

    事件

    iOS 将事件分为三类:

    • Touch
    • Motion
    • Remote
      像耳机线控……

    Touch 事件

    Touch 事件的过程:事件产生 ==》 事件分发 ==》 事件响应

    事件产生

    iOS每产生一个事件都会生成一个 UIEvent 对象,它记录了事件的类型( UIEventType / UIEventSubtype (主要用在Motion和Remote) )、时间、几个手指触控等信息
    当手指触摸屏幕时,每个手指都会产生一个 UITouch 对象,它保存着跟手指相关的信息,如触摸的位置、时间、阶段( UITouchPhase )等
    UIEvent 和 UITouch 关系 -- UIEvent 有一方法 - allTouches ,返回 NSSet 集合的一组 UITouch 对象,即一个 UIEvent 包含一个或多个 UITouch 对象

    确定点击对象

    Hit Test -- iOS 通过 Hit Test 来寻找触摸点下面的 view 是什么

    [UIView class]
    - hitTest:withEvent:
    

    Hit Test小结:

    • 从 UIWindow 开始,先父 view 后子 view
    • subViews 按照逆顺序遍历
    • 在代码中是嵌套调用

    如上图,当我们点击 view4 的区域,有
    hit test from view TestWindow
    hit test from view 0
    hit test from view 2
    return hit view (null), self view 2
    hit test from view 1
    hit test from view 4
    return hit view 4, self view 4
    return hit view 4, self view 1
    return hit view 4, self view 0
    return hit view 4, self view TestWindow
    

    事件分发

    UIApplication 和 UIWindow 有方法 - sendEvent: ,用于把事件分发到 hitTest View

    UIApplication == sendEvent: ==> UIWindow == sendEvent: ==> hitTest View

    事件响应

    能响应事件的类必须继承于一个类 -- UIResponder,UIApplication / UIViewController / UIView( UI ) / AppDelegate 都继承于 UIResponder
    通常来说,我们首先找到的 hitTest View,就是 Touch 事件的第一个 Responder

    UIResponder 的响应过程

    触摸开始 ==》 触摸移动 ==》 触摸结束 ,还有触摸取消

    - touchesBegan:withEvent:
    - touchesMoved:withEvent:
    - touchesEnded:withEvent:
    - touchesCancelled:withEvent:
    
    UIResponder 的响应顺序

    响应链 ( Responder Chain ) 即一系列关联的响应对象 ( a series of linked responder objects )
    first responder ==> next responder ==> ... ==> UIWindow ==> UIApplication ==> AppDelegate ==> 丢弃
    subView/hitTestView ==> superView/VC.view ==> VC ==> VC' superView ==> root VC ==> window ==> application ==> AppDelegate ==> 丢弃

    • 如果想事件继续传递下去,可以调用 [super touchesBegan:touches withEvent:event],不建议直接调 [self.nextResponder touchesBegan:touches withEvent:event]
    UIView 不响应事件的条件
    • userInteractionEnabled = NO
    • hidden = YES
    • alpha ( 0-0.01 )

    UIView 加大点击区域

    假设一个按钮,希望能在其显示区域的一定范围外,也能响应点击事件

    • 最直观的做法:加大透明按钮
    • 事件机制 hitTest
      在父 view 的 - hitTest:withEvent: 方法中,判断如果点击的point 在要求的 rect 中时,直接返回 button ,否则返回 [super hitTest:point withEvent:event] 继续传递
      • pointInside:withEvent:
    • hitTest:withEvent: 方法会递归地调用 - pointInside:withEvent: 方法,- pointInside:withEvent: 用来判断触摸的 point 是否在 view 的范围内
      button 可以重写这一方法
    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
        CGFloat buttonExtraPadding = 20;
    
        CGPoint convertPoint = [self convertPoint:point toView:self.superview];
        CGRect targetRect = CGRectInset(self.frame, - buttonExtraPadding, - buttonExtraPadding);
        if (CGRectContainsPoint(targetRect, convertPoint))
        {
            return YES;
        }
    
        return [super pointInside:point withEvent:event];  
    }
    

    子 view 超过父 view 范围

    当子 view 超出父 view 的范围时,在父 view 范围内的部分能够响应事件,超出父 view 部分则不能响应事件
    因为在 hitTest View 时,父 view 的 hitTest View 监测到不在范围内,因而也不会递归调用到子 view 的 hitTest

    // 重写父 view 的 - pointInside:withEvent: 方法,使当确定 point 在子 view 范围内时,返回 YES
    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
        // point 需要转换到子 view 的坐标系
        if ([_button pointInside:[self convertPoint:point toView:_button] withEvent:event])
        {
            return YES;
        }
    
        return [super pointInside:point withEvent:event];
    }
    

    全局监控 touch 事件

    • UIWindow 子类
      UIWindow 有 - sendEvent: 方法,可以捕获到所有的 Touch 事件

    相关文章

      网友评论

          本文标题:iOS 事件机制

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