132

Let's say you have a parent widget that might have a variable size.

For example:

var container = new Container(
   height: 200.0, // Imagine this might change
   width: 200.0, // Imagine this might change
   // Imagine content in this container will 
   // depend on the parent container
   child: new Container(), 
);

And maybe you want to have the child of the parent container render something different based on the size that it's given.

Think of responsive design breakpoints, if the width is over X use this layout, if the width is under X use that layout.

What's the best way to do this in Flutter?

Dvdwasibi
  • 10,537
  • 7
  • 22
  • 22
  • the flutter wiki references a couple ways to do this: https://github.com/flutter/flutter/wiki/Creating-Responsive-Apps – Aaron Sep 17 '17 at 11:50

5 Answers5

221

You will want to use the LayoutBuilder widget which will build at layout time and provides the parent widget's constraints.

The LayoutBuilder takes in a build() function which has the the standard BuildContext along with the BoxConstraints as parameters that can be used to help dynamically render widgets based on size.

Let's build a simple example of widget that renders "LARGE" if the parent width is greater than 200px and "SMALL" if the parent width is less or equal to that.

var container = new Container(
  // Toggling width from 100 to 300 will change what is rendered
  // in the child container
  width: 100.0,
  // width: 300.0
  child: new LayoutBuilder(
    builder: (BuildContext context, BoxConstraints constraints) {
      if(constraints.maxWidth > 200.0) {
        return new Text('BIG');
      } else {
        return new Text('SMALL');
      }
    }
  ),
);
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
Dvdwasibi
  • 10,537
  • 7
  • 22
  • 22
  • Thanks, I have struggled for a whole to layout a widget basing on the size of the parent widget, first I was trying to use screen height minus appbar height and bottom bar height, which is stupid and not working on all physical phones. – Daniel Dai Mar 28 '19 at 01:59
  • 1
    What if the widget requires a width and height? How can I set it to the parent's size? – Dpedrinha Sep 20 '19 at 17:58
  • 7
    This is great except constraints are different from size. This becomes evident when you're trying to get the size of a widget inside of a `Scrollable`. If you have a `ListView` and you try to get the vertical constraints of one of its children, it'll give you a `maxHeight` of double.infinity and a `minHeight` of 0.0. – ThinkDigital Nov 01 '19 at 03:24
  • Uhhh! thanks a lot – Rajesh Nov 03 '21 at 14:15
  • the code inside where the if statement is is never called, so how does this work? – 68060 Jan 04 '23 at 05:58
  • 1
    @68060 Notice that the `width: 300.0` is commented out, so if you uncomment that line (ie, changing width from 100 to 300), the if statement will be called. – satvikpendem Feb 07 '23 at 04:44
  • You emphasized "at layout time" - could you please explain as opposed to what? and does it has any implications on performance? – developer82 Jul 04 '23 at 13:23
11

Put the widget in a container and set its width and/or height to double.maxFinite

Example:

 child: Container(
     width: double.maxFinite,
   )
4

So I had an interesting situation where my parent child was increasing size dynamically based on the content (Text containing description). This parent widget was displaying content in read only mode but this solution might resolve other problems as well where you increase textfield height dynamically.

I had a height variable and GlobalKey. In initState of widget I am using SchedulerBinding which runs it's addPostFrameCallback after layout is build.

The globalKey is assigned to any parent widget whose height we need for it's children.

double height = 0.0;
GlobalKey _globalKey = GlobalKey();

  @override
  void initState() {
    SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
      height = _globalKey.currentContext.size.height;
      print('the new height is $height');
      setState(() {});
    });
    super.initState();
  }

and rest code looks like this

// this parent having dynamic height based on content 
Container(
  width: 100.0,
  key: _globalKey,
  child: Container(
    width: 100.0,
    child: Row(children: [  ///  you can have column as well or any other widget. 
      Container(child: ...),
      Container(height: height,), ///this widget will take height from parent 
    ],),
  )
)
Muhammad Adil
  • 4,358
  • 3
  • 32
  • 36
  • do you know how can I use this if I have many message bubbles instead of just one? – scott lee Jun 25 '21 at 14:03
  • 1
    @scottlee Interesting question, I am already working on it right now :) . I need that for comments. I guess solution would be having that bubble as a separate widget and using StreamBuilder would help. As soon as you know building of widget is complete you can send that height to a particular widget through StreamBuilder. I am sure this would help. – Muhammad Adil Jun 25 '21 at 16:28
  • @scottlee so I have given this a try and it has worked perfectly. Let me know how you are working on it, I might provide you a solution. – Muhammad Adil Jun 26 '21 at 10:37
1

you can try the IntrinsicHeight widget:

https://api.flutter.dev/flutter/widgets/IntrinsicHeight-class.html

for me this was the simplest solution. But it seems to be expensive, so you should avoid it when possible

var container = Container(
height: 200.0, // Imagine this might change
width: 200.0, // Imagine this might change

child: IntrinsicHeight(
      child: Container()), 
);
th_lo
  • 461
  • 3
  • 18
-17

To set the widget size dynamically according to parent, use below code:

Container(
  color: Colors.red,
  alignment: Alignment.center,
  child: Wrap(children: <Widget>[

    GestureDetector(
      child: Text(
        'Button',
        style: TextStyle(
            color: Color(0xff0079BF), fontSize:20),
      ),
      onTap: () {


        Navigator.pushReplacementNamed(context, '/signin');
      },
    ),


    Text(
      'You have pushed the button this many times:',
      style: TextStyle(fontSize: 50),
    ),

  ]),
)

I hope this solutions will work for you.

ZealousWeb
  • 1,647
  • 1
  • 10
  • 11