iOS日常开发

iOS事件响应链

2017-06-30  本文已影响25人  风与鸾

前言

当用户点击付款跳转到付款界面、点击扫一扫进入扫描二维码视图。
当我们点击屏幕的时候,这个点击事件由硬件层传向iPhone OS(操作系统),
然后操作系统把这些信息包装成UITouch(点击对象)和UIEvent(事件对象),然后找到当前运行的程序,
逐级寻找能够响应这次事件的响应者,这一寻找过程称为事件的响应链。
过程:AppDelegate -> UIApplication -> UIWindow ->UIController(UIResponder子类)-UIView->subViews

查找和响应流程.jpg

Hit-test View

决定谁是Hit-test View通过不断递归- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event以下两个函数实现的:

// recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

// default returns YES if point is in bounds
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

Hit-test检查机制

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
   if (self.alpha <= 0.01 || !self.userInteractionEnabled || self.hidden) { 
      return nil; 
   } 
   BOOL inside = [self pointInside:point withEvent:event]; 
   UIView *hitView = nil; 
   if (inside) { 
      NSEnumerator *enumerator = [self.subviews reverseObjectEnumerator]; 
      for (UIView *subview in enumerator) { 
          hitView = [subview hitTest:point withEvent:event]; 
          if (hitView) { 
              break; 
          } 
      } 
      if (!hitView) { 
        hitView = self; 
      } 
      return hitView; 
  }else{ 
      return nil; 
  }
}

事件分发处理

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;

实际运用

//in custom button .m
//overide this method
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event {
    return CGRectContainsPoint(HitTestingBounds(self.bounds, self.minimumHitTestWidth, self.minimumHitTestHeight), point);
}

CGRect HitTestingBounds(CGRect bounds, CGFloat minimumHitTestWidth, CGFloat minimumHitTestHeight) {
    CGRect hitTestingBounds = bounds;
    if (minimumHitTestWidth > bounds.size.width) {
        hitTestingBounds.size.width = minimumHitTestWidth;
        hitTestingBounds.origin.x -= (hitTestingBounds.size.width - bounds.size.width)/2;
    }
    if (minimumHitTestHeight > bounds.size.height) {
        hitTestingBounds.size.height = minimumHitTestHeight;
        hitTestingBounds.origin.y -= (hitTestingBounds.size.height - bounds.size.height)/2;
    }
    return hitTestingBounds;
}
上一篇 下一篇

猜你喜欢

热点阅读