In some cases, we need to get the size or location information of the Widget. But the Widget object itself does not have size and location data, so to get the size and location information of the Widget, you need to get it through the RenderBox object associated with the Widget object.

It’s time to get the size and location of the Widget.

Get the RenderBox object

To get a RenderBox object, it’s pretty simple. Just call the findRenderObject method of BuildContext. The code is as follows.

// Context is a BuildContext object
RenderBox renderBox = context.findRenderObject();
Copy the code

But sometimes, we don’t get the BuildContext object right, so what do we do? In this case, you need to set a Key for the Widget object, and then use that Key to get the BuildContext object, which in turn gets the RenderBox object, as follows.

class MyHomePageState extends State<MyHomePage> {
  // Define a key
  GlobalKey _key = GlobalKey();
  _getRenderBox() {
    // Get the 'RenderBox' object
    RenderBox renderBox = _key.currentContext.findRenderObject();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          Flexible(
            flex: 2,
            child: Container(
              / / set the keykey: _key, color: Colors.red, ), ), ], ), ); }}Copy the code

However, when we use the initState method, we will find that the RenderBox object will not succeed and will report an error. Why is that? In fact, when the initState method is called, the Widget has not yet completed rendering, so it cannot get the RenderBox object. You just need to wait for the Widget to finish rendering. The code is as follows.

class MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    // Listen to whether the Widget has been drawn
    WidgetsBinding.instance.addPostFrameCallback(_getRenderBox);
    super.initState();
  }
  // Define a key
  GlobalKey _key = GlobalKey();
  _getRenderBox(_) {
    // Get the 'RenderBox' object
    RenderBox renderBox = _key.currentContext.findRenderObject();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          Flexible(
            flex: 2,
            child: Container(
              / / set the keykey: _key, color: Colors.red, ), ), ], ), ); }}Copy the code

Get the size of the Widget

Once you get the RenderBox object associated with the Widget object, you can easily get the size of the Widget. The code is as follows.

Size size = renderBox.size;
Copy the code

Let’s look at an example.

class HomeState extends State<HomeWidget> {
  @override
  void initState() {
    // Listen to whether the Widget has been drawn
    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
    super.initState();
  }

  void _afterLayout(_) {
    _getSizes();
  }

  _getSizes() {
    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
    final sizeRed = renderBoxRed.size;
    // Output the width and height of the widget with a red background
    print("size of red:$sizeRed");
    final RenderBox renderBoxBlue = _keyBlue.currentContext.findRenderObject();
    final sizeBlue = renderBoxBlue.size;
    // Output the width and height of the widget with a blue background
    print("size of Blue:$sizeBlue");
    final RenderBox renderBoxAmber =_keyAmber.currentContext.findRenderObject();
    final sizeAmber = renderBoxAmber.size;
    // Output the width and height of the widget with the background
    print("size of Amber:$sizeAmber");
  }

  GlobalKey _keyRed = GlobalKey();
  GlobalKey _keyBlue = GlobalKey();
  GlobalKey _keyAmber = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Flexible(
          key: _keyRed,
          flex: 1,
          child: Container(
            color: Colors.red,
          ),
        ),
        Flexible(
          key: _keyBlue,
          child: Container(
            color: Colors.blue,
          ),
          flex: 2,
        ),
        Container(
          key: _keyAmber,
          width: 300,
          height: 200, color: Colors.amber, ), ], ); }}Copy the code

Run the above code to get the width and height of the Widget. The output is as follows.

size of red:Size(411.4.134.5)
size of Blue:Size(411.4.269.0)
size of Amber:Size(300.0.200.0)
Copy the code

As you can see, the acquired width and height are device independent.

3. Get the location of the Widget

Getting the location of a Widget is as simple as getting its width and height; you just need to call a different API. As follows.

Offset offset = renderBox.localToGlobal(Offset.zero);
Copy the code

Let’s look at an example.

class HomeState extends State<HomeWidget> {
  @override
  void initState() {
    // Listen to whether the Widget has been drawn
    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
    super.initState();
  }

  void _afterLayout(_) {
    _getPositions();
  }

  _getPositions() {
    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
    final positionsRed = renderBoxRed.localToGlobal(Offset(0.0));
    print("positions of red:$positionsRed");
    final RenderBox renderBoxBlue = _keyBlue.currentContext.findRenderObject();
    final positionsBlue = renderBoxBlue.localToGlobal(Offset(0.0));
    print("positions of Blue:$positionsBlue");
    final RenderBox renderBoxAmber =
    _keyAmber.currentContext.findRenderObject();
    final positionsAmber = renderBoxAmber.localToGlobal(Offset(0.0));
    print("positions of Amber:$positionsAmber");
  }

  GlobalKey _keyRed = GlobalKey();
  GlobalKey _keyBlue = GlobalKey();
  GlobalKey _keyAmber = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Flexible(
          key: _keyRed,
          flex: 1,
          child: Container(
            color: Colors.red,
          ),
        ),
        Flexible(
          key: _keyBlue,
          child: Container(
            color: Colors.blue,
          ),
          flex: 2,),// The Widget is displayed in the center
        Container(
          key: _keyAmber,
          width: 300,
          height: 200, color: Colors.amber, ), ], ); }}Copy the code

Run the above code to get the location of the Widget. The output is as follows.

positions of red:Offset(0.0.80.0)
positions of Blue:Offset(0.0.214.5)
positions of Amber:Offset(55.7.483.4)
Copy the code

The Flutter, like Android, starts at the top left of the screen. The output above is the distance of the Widget from the beginning of the coordinate system. See the figure below.

4, summarize

With the above code, you can get the size and location information of the Widget, which can be very useful in many cases. In particular, when we implement the click, gesture and other events of a custom Widget, we need the location information to obtain the location of the event in the Widget.

[Reference]

Flutter : Widget Size and Position