美文网首页
iOS 事件传递和事件响应

iOS 事件传递和事件响应

作者: QG不吃鱼的猫 | 来源:发表于2020-05-18 16:39 被阅读0次

    关键点:hitTest:withEvent方法的底层实现

    //point是该试图的坐标系上的点
    -(UIView *)hitTest:(CGpoint)point withEvent:(UIEvent *)event {
      //判断自己是否接受触摸事件
      if(self.userInteractionEnable = NO || self.hidden = YES || self.alpha <= 0.01) return nil;
      //判断触摸点在不在自己的范围内
      if(![self pointInside:point withEvent:event]) return nil;
      int count = self.subviews.count;
      //从后往前便利自己的控件,看是否有子空间更适合响应此事件
      for(int i = count - 1;i >=0;i--){
            UIView *childView  = self.subviews[i];
            CGPoint childPoint  = [self convertPoint:point toView:childView];
            UIView *fitView        = [childView hitTest:childPoint   withEvent:event];
    
              if(fitView) {
                  return fitView;
              }
      }
       //没有找到比自己更合适的view
       return self;
    }
    
    • 总结几个点

    1、在hitTest:消息分发过程中,并不是所有包含了触摸点的view都会经历事件传递,只有pointInside返回YES的view才属于响应者链条。
    2、响应者是什么?继承了UIResponder的对象称为响应者对象,能够处理touchesBegan等事件。很多响应者链接在一起的组合的一个链条称为响应者链条。
    3、重写hitTest和pointInside可以做到好多功能。

    使用案例

    1、例如不想让某个视图响应事件,只需要重写pointInside:withEvent:方法,让此方法返回NO就行了。
    2、隔层透传
    3、扩大点击区域

    2、响应者链条使用案例

    • 使用响应者链条找到当前view所属的控制器
          - (UIViewController *)parentController {
              UIResponder *responder = [self nextResponder];
               while(responder){
                      if([responder isKindofClass:[UIViewController class]]) {
                            return (UIViewController *)responder;
                       }
                       responder = [responder nextResponder];
                }
                return nil;
           }
    
    

    3、nextResponder

    链条:
    subview->view->viewController->window->application->AppDelegate->nil

    4、系统事件source0?那它是如何唤醒mainThread的runloop的呢?

    • 1、用户触发事件, IOKit.framework 生成一个 IOHIDEvent 事件并由 SpringBoard 接收,SpringBoard会利用mach port,产生source1,来唤醒目标APP的com.apple.uikit.eventfetch-thread的RunLoop。
    • 2、 Eventfetch thread会将main runloop 中__handleEventQueue所对应的source0设置为signalled == Yes状态,同时唤醒main RunLoop。mainRunLoop则调用__handleEventQueue进行事件队列处理。

    相关文章

      网友评论

          本文标题:iOS 事件传递和事件响应

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