hitTest method

  1. @override
bool hitTest(
  1. BoxHitTestResult result, {
  2. required Offset position,
})
override

Determines the set of render objects located at the given position.

Returns true, and adds any render objects that contain the point to the given hit test result, if this render object or one of its descendants absorbs the hit (preventing objects below this one from being hit). Returns false if the hit can continue to other objects below this one.

The caller is responsible for transforming position from global coordinates to its location relative to the origin of this RenderBox. This RenderBox is responsible for checking whether the given position is within its bounds.

If transforming is necessary, BoxHitTestResult.addWithPaintTransform, BoxHitTestResult.addWithPaintOffset, or BoxHitTestResult.addWithRawTransform need to be invoked by the caller to record the required transform operations in the HitTestResult. These methods will also help with applying the transform to position.

Hit testing requires layout to be up-to-date but does not require painting to be up-to-date. That means a render object can rely upon performLayout having been called in hitTest but cannot rely upon paint having been called. For example, a render object might be a child of a RenderOpacity object, which calls hitTest on its children when its opacity is zero even though it does not paint its children.

Implementation

@override
bool hitTest(BoxHitTestResult result, {required Offset position}) {
  if (!hasSize) {
    // 如果尚未有 size, 依照正常會拋出錯誤
    // 這邊不處理直接往上丟
    return super.hitTest(result, position: position);
  }

  // 我們要處理除了目標之外的所有點擊, 目標是點擊穿透
//    print('是否接受點擊: $position');

  switch (rule) {
    case TouchRule.allThrough:
      // 完全穿透
      return false;
    case TouchRule.otherIntercept:
      // 檢測範圍穿透, 其餘攔截
      if (child!.size.contains(position)) {
        // 在子元件範圍
        // 檢查結果列表是否包含 TouchDetectBox
        super.hitTest(result, position: position);
        final isDetected = result.path
            .whereType<BoxHitTestEntry>()
            .any((e) => e.target is TouchDetectBox);
//          print("是否包含需要檢測的子元件: $isDetected");
        if (isDetected) {
          // 檢測範圍抓到了, 但因為需要穿透, 因此需要清除並回傳不處理
          (result.path as List).clear();
          return false;
        } else {
          return true;
        }
      }
      return false;
    case TouchRule.detectIntercept:
      // 檢測範圍攔截, 其餘穿透
      if (child!.size.contains(position)) {
        // 在子元件範圍
        // 檢查結果列表是否包含 TouchDetectBox
        final resultHandle = super.hitTest(result, position: position);
        final isDetected = result.path
            .whereType<BoxHitTestEntry>()
            .any((e) => e.target is TouchDetectBox);
//          print("是否包含需要檢測的元件: $isDetected");
        if (isDetected) {
          return resultHandle;
        } else {
          (result.path as List).clear();
//            print("清除結果: ${result.path.length}");
          return false;
        }
      }
      return false;
    case TouchRule.allIntercept:
      // 完全攔截
      return super.hitTest(result, position: position);
  }
}