devtools icon indicating copy to clipboard operation
devtools copied to clipboard

Doubts about the implementation method of hitTest in widgetInspector

Open yanyanran opened this issue 1 year ago • 0 comments

why does the hitTest method overridden in widgetInspector need to be sorted? Logically speaking, what you get in hitTestHelper should be the traversal result of the entire renderObject tree. Because tree traversal is depth-first, the deepest hit node should be located first in the result array. But the result is not like this after removing sort in hitTest. What is the reason?

code:

List<RenderObject> hitTest(Offset position, RenderObject root) {
    final List<RenderObject> regularHits = <RenderObject>[];
    final List<RenderObject> edgeHits = <RenderObject>[];

    _hitTestHelper(regularHits, edgeHits, position, root, root.getTransformTo(null));
    double area(RenderObject object) {
      final Size size = object.semanticBounds.size;
      return size.width * size.height;
    }
    regularHits.sort((RenderObject a, RenderObject b) => area(a).compareTo(area(b))); 
    final Set<RenderObject> hits = <RenderObject>{
      ...edgeHits,
      ...regularHits,
    };
    return hits.toList();
  }

  bool _hitTestHelper(
      List<RenderObject> hits,
      List<RenderObject> edgeHits,
      Offset position,
      RenderObject object,
      Matrix4 transform,
      ) {
    bool hit = false;
    final Matrix4? inverse = Matrix4.tryInvert(transform);
    if (inverse == null) {
      return false;
    }
    final Offset localPosition = MatrixUtils.transformPoint(inverse, position);

    final List<DiagnosticsNode> children = object.debugDescribeChildren();
    for (int i = children.length - 1; i >= 0; i -= 1) {
      final DiagnosticsNode diagnostics = children[i];
      if (diagnostics.style == DiagnosticsTreeStyle.offstage ||
          diagnostics.value is! RenderObject) {
        continue;
      }
      final RenderObject child = diagnostics.value! as RenderObject;
      final Rect? paintClip = object.describeApproximatePaintClip(child);
      if (paintClip != null && !paintClip.contains(localPosition)) {
        continue;
      }

      final Matrix4 childTransform = transform.clone();
      object.applyPaintTransform(child, childTransform);
      if (_hitTestHelper(hits, edgeHits, position, child, childTransform)) {
        hit = true;
      }
    }

    final Rect bounds = object.semanticBounds;
    if (bounds.contains(localPosition)) { 
      hit = true;  
      if (!bounds.deflate(_edgeHitMargin).contains(localPosition)) {  
        edgeHits.add(object);  
      }
    }
    if (hit) {
      hits.add(object);
    }
    return hit;
  }

yanyanran avatar Jun 21 '24 03:06 yanyanran