kaboc
kaboc

Reputation: 844

How to get inside a widget the resulting size of itself shrinked by FittedBox

In the code below, a row of two 300x300 boxes (_Box) wrapped with FittedBox shrinks to fit in the screen. As a result, each box becomes smaller than 300x300.

However, if I get the width of a box in the build() method of _Box using RenderBox.size and LayoutBuilder(), the obtained size is 300.0 and Infinity respectively.

How can I get the actual displayed size?

I'd like to get it inside the _Box class, without it getting passed from the parent.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: FittedBox(
            child: Row(
              children: <Widget>[
                _Box(Colors.red),
                _Box(Colors.orange),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _Box extends StatelessWidget {
  const _Box(this.color);

  final Color color;

  @override
  Widget build(BuildContext context) {
    RenderBox renderBox = context.findRenderObject();
    print(renderBox?.size?.width);  // 300.0

    return LayoutBuilder(
      builder: (_, constraints) {
        print(constraints.maxWidth);  // Infinity

        return Container(
          width: 300,
          height: 300,
          color: color,
        );
      },
    );
  }
}

Upvotes: 1

Views: 833

Answers (2)

kaboc
kaboc

Reputation: 844

I'll answer my own question, although it is not a direct answer.

I couldn't find a way to get the size shrinked by FittedBox, but I realised that I was able to get around it by using Flexible instead.

SafeArea(
  child: Row(
    children: const [
      Flexible(
        child: _Box(Colors.red),
      ),
      Flexible(
        child: _Box(Colors.orange),
      ),
    ],
  ),
);
@override
Widget build(BuildContext context) {
  return ConstrainedBox(
    constraints: const BoxConstraints(maxWidth: 300.0),
    child: AspectRatio(
      aspectRatio: 1.0,
      child: ColoredBox(color: color),
    ),
  );
}

It still seems impossible to get the size via RenderBox, and it is now possible with LayoutBuilder. But either way, I didn't need them.

The constraints of the two boxies are shrinked by Flexible if a smaller space is available, but they expand as big as the space allows, so I limited the maximum size using ConstrainedBox and AspectRatio.

I didn't have to stick to FittedBox. I think I was obsessed with the idea of using it and couldn't think of other solutions when I posted the question two years ago.

Upvotes: 0

Blend3rman
Blend3rman

Reputation: 185

The Flutter constraints object is used to limit how large or small a widget can be rendered, and is usually never really used to get the current size of the widget.

The renderBox.size object is of Size class, and as a result it has both renderBox.size.width and renderBox.size.height as defined getters. Note that these values can only be set once the layout phase of the current view is over: see the findRenderObject() docs page.

This means that you will have to avoid calling findRenderObject() from the build() method. Instead you will have to define a callback function that must execute after the layout process is complete. You can do this using that have widgets that have callback functions like onTap or onSelected. How you implement this and finally get the actual layout size by running the callback function is totally dependent on your use case.

Further recommended reading:

  1. DevelopPaper - Sample code for getting the width and height of screen and widget in Flutter
  2. Flutter on Github - How to get a height of a widget? #16061
  3. Rémi Rousselet's amazing answer explaining his workaround (using an Overlay widget)

Upvotes: 1

Related Questions