How to get transformed widget real position on screen

Issue

Let’s say I have a container with a transform applied to it. Because of the transform it’s drawn to a slightly shifted position on screen (while its layout position remain the original one, without the transform).

Eg:
Here I have two containers in a stack. Blue one is without transform. And red one is with transform.

enter image description here

https://dartpad.dev/?id=5fc0a808ea606a97216bb06df0824b77&null_safety=true

How do I determine actual position of red one on screen? Since transform is applied at the paint time (not layout time), the usual ways of getting renderobject and using it to obtain position relative to ancestor doesn’t work. It just gives same rect for both.

Blue Rect Rect.fromLTRB(0.0, 0.0, 400.0, 400.0)
Red Rect Rect.fromLTRB(0.0, 0.0, 400.0, 400.0) 

Is there any way to get the actual position of red/transformed widget relative to ancestor/screen?

Solution

Finally found a way. You just need to find a child renderobject which is actually positioning things.

// function to get relative rect from ancestor
Rect getRenderBoxRect(RenderBox rb, RenderObject ancestor) {
    final size = rb.size;
    final topLeft = rb.localToGlobal(Offset.zero, ancestor: ancestor);
    final bottomRight =
        rb.localToGlobal(Offset(size.width, size.height), ancestor: ancestor);
    return Rect.fromPoints(topLeft, bottomRight);
  }

// function to get specific type of child renderobject
RenderObject? findRenderObjectByType(RenderObject parent, Type type) {
    RenderObject? found;
    parent.visitChildren((child) {
      if (found != null) {
        return;
      }

      if (child.runtimeType == type) {
        found = child;
        return;
      }
      found ??= findRenderObjectByType(child, type);
    });
    return found;
  }

// then calculate rect in post frame callback using global key
Widget build(BuildContext context) {
    WidgetsBinding.instance?.addPostFrameCallback((duration) {
      final ancestor = stackKey.currentContext!.findRenderObject()!;
      final redRo = redKey.currentContext!.findRenderObject()!;
      final redRoT = findRenderObjectByType(redRo, RenderPositionedBox);
      if (redRoT != null) {
        print("RECT ${getRenderBoxRect(redRoT as RenderBox, ancestor)}");
      }
    }
}

Prints:
RECT Rect.fromLTRB(200.0, 0.0, 683.0, 500.0)

This gives you the rect for real position (black border in the following image):
enter image description here

Answered By – Krishna Kant Sharma

Answer Checked By – Candace Johnson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.