getRectOfSemanticsNodeInViewCoordinates method

  1. @override
Rect? getRectOfSemanticsNodeInViewCoordinates(
  1. int viewId,
  2. int nodeId
)
override

Returns the global rect for the semantics node with the given nodeId in the view with the given viewId.

The rect is in the global coordinate space of the view's render tree, in logical pixels. This is useful for widgets that react to semantics actions and need the on-screen position of the semantics node that received the action.

Asserts in non-release builds and returns null if the view is unknown, the view has no semantics owner, or the node cannot be found. Callers should only invoke this in response to a semantics action, in which case all three lookups are expected to succeed.

Implementation

@override
ui.Rect? getRectOfSemanticsNodeInViewCoordinates(int viewId, int nodeId) {
  final RenderView? renderView = _viewIdToRenderView[viewId];
  assert(
    renderView != null,
    'getRectOfSemanticsNodeInViewCoordinates was called for unknown view $viewId.',
  );
  if (renderView == null) {
    return null;
  }

  final SemanticsOwner? semanticsOwner = renderView.owner?.semanticsOwner;
  assert(
    semanticsOwner != null,
    'getRectOfSemanticsNodeInViewCoordinates was called for view $viewId, but the view does not have a '
    'SemanticsOwner. Semantics must be enabled for the lookup to succeed.',
  );
  if (semanticsOwner == null) {
    return null;
  }

  final SemanticsNode? node = semanticsOwner.getSemanticsNode(nodeId);
  assert(
    node != null,
    'getRectOfSemanticsNodeInViewCoordinates was called for unknown node $nodeId in view $viewId.',
  );
  if (node == null) {
    return null;
  }

  var transform = Matrix4.identity();
  SemanticsNode? current = node;
  while (current != null) {
    if (current.transform != null) {
      transform = current.transform! * transform as Matrix4;
    }
    current = current.parent;
  }

  // The walk above accumulates RenderView's root transform, which scales
  // from logical to physical pixels. Undo it with the same matrix the
  // framework applied, so the result is in logical pixels regardless of
  // what that matrix encodes.
  final rootInverse = Matrix4.copy(renderView.configuration.toMatrix())..invert();
  transform = rootInverse * transform as Matrix4;

  return MatrixUtils.transformRect(transform, node.rect);
}