Deborah
Deborah

Reputation: 4575

flutter - correct way to create a box that starts at minHeight, grows to maxHeight

I have a container that I want to start off at a minimum size and grow (if its contents grow while user is adding content) to a maximum size, then stop.

The correct widget for this seems to be ConstrainedBox, like so:

new ConstrainedBox(
  constraints: new BoxConstraints(
    minHeight: 35.0,
    maxHeight: 60.0,
  ),
  child: ...child with growing content (has default height 25.0)...
),

however, this starts the box off at the maxHeight.

I tried to use hasBoundedHeight, but can not seem to construct the correct syntax for it or find an example in documentation.

What is the best way to get the box working as described?

Upvotes: 156

Views: 206384

Answers (8)

Rémi Rousselet
Rémi Rousselet

Reputation: 277527

There's no notion of "Starts from max/min size".

The thing is, ConstrainedBox only add constraints to it's child. But in the end, it doesn't pick a size.

If you want your child to hit minSize, then they have to not expend. Which translate into not having a width/height of double.INFINITY. Fact is that double.INFINITY is the default value of many widgets, including Container.

On the other hand, some widgets such as DecoratedBox have a default size of 0. Which means that this code :

return new ConstrainedBox(
  constraints: new BoxConstraints(
    minHeight: 5.0,
    minWidth: 5.0,
    maxHeight: 30.0,
    maxWidth: 30.0,
  ),
  child: new DecoratedBox(
    decoration: new BoxDecoration(color: Colors.red),
  ),
);

Will render a 5.0*5.0 red square.

Upvotes: 254

AnasSafi
AnasSafi

Reputation: 6284

Let me explain:

If child of BoxConstraints is (Column widget) or (ListView widget), maxHeight will not work as expected, it will work as height, to solve that:

1 - If child of BoxConstraints is Column, your code need to be like this:

 Container(
    constraints: BoxConstraints(
      maxHeight: MediaQuery.of(context).size.height * .30
    ),
    child: SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.min,
  
        children: const [
          // growable childrens
        ],
      ),
    ),
);

2- If child of BoxConstraints is ListView, your code need to be like this:

Container(
  constraints: BoxConstraints(
    maxHeight: MediaQuery.of(context).size.height * .20,
  ),
  child: ListView(
    scrollDirection: Axis.vertical,
    shrinkWrap: true,
    children: const [
      // growable childrens
    ],
  ),
);

As is the case if child of BoxConstraints is Row, maxWidth will not work as expected, it will work as width, to solve that you need to set mainAxisSize to MainAxisSize.min like this:

 Container(
    constraints: BoxConstraints(
      maxWidth: MediaQuery.of(context).size.width * .15
    ),
    child: SingleChildScrollView(
      child: Row(
        mainAxisSize: MainAxisSize.min,
  
        children: const [
          // growable childrens
        ],
      ),
    ),
);

Upvotes: 8

Jitesh Mohite
Jitesh Mohite

Reputation: 34250

Below Example will help you to grow Size of the widget as required

Container(
          color: Colors.blueAccent,
          constraints: BoxConstraints(
              minHeight: 100, minWidth: double.infinity, maxHeight: 400),
          child: ListView(
            shrinkWrap: true,
            children: <Widget>[
              ...List.generate(
                10,  // Replace this with 1, 2 to see min height works. 
                (index) => Text(
                  'Sample Test: ${index}',
                  style: TextStyle(fontSize: 60, color: Colors.black),
                ),
              ),
            ],
          ),
        ),

Output for Min Height for Single Item:

enter image description here

Output for Min Height for 10 Items:

enter image description here

Note: This will show widgets as per mentioned max-height.

Upvotes: 49

Anuj Kumar
Anuj Kumar

Reputation: 21

try to use Contraints box instead of Sized box because sized box have not min height and min width property they just have height and width property

 ConstrainedBox(
      constraints: const BoxConstraints(
        maxHeight: Dimension.d9,
        minHeight: Dimension.d9,
        maxWidth: 144.0
      ),
    );

Upvotes: 0

qix
qix

Reputation: 7952

As Remi's answer points out, if your ConstrainedBox is initially maxing out a dimension when you expected it to be closer to or at the min, it's because a child wants to be big. (Re: Constraints go down. Sizes go up. Parent sets position.) If you aren't sure which child is causing it, one handy way is to use the Widget Inspector in your IDE and check the properties of the descendants, then check the docs as to why and adjust accordingly.

For example, I've run into this e.g. when wrapping a widget in Center. Normally without constraints the centered widget would match the child's height. However, when putting the Center inside a ConstrainedBox, all of a sudden it blew up to the max constraints. After checking the docs, I saw that:

  1. This widget will be as big as possible if its dimensions are constrained and widthFactor and heightFactor are null, explaining the new layout.
  2. But: If a dimension is unconstrained and the corresponding size factor is null then the widget will match its child's size in that dimension, which explains the behavior without the ConstrainedBox.
  3. And this tells me how to fix it: If a size factor is non-null then the corresponding dimension of this widget will be the product of the child's dimension and the size factor, i.e. set the Center's heightFactor: 1.

So pay attention to how your children behave! If you impose external constraints, they may be greedy (or not, just like real kids ;).

Upvotes: 1

Rodion Mostovoi
Rodion Mostovoi

Reputation: 1593

For Column for example, minHeight is not working. I solved it using this hack:

ConstrainedBox(
  constraints: BoxConstraints(minHeight: 150),
  child: Stack(
    children: [
      Column(
        children: [dynamicChild1, dynamicChild2],
      ),
    ],
  ),
);

So, just by wrapping Column in Stack. Now the Column size became 150 and more.

Upvotes: 4

K Y M
K Y M

Reputation: 21

Yes, ConstrainedBox is the right widget for the purpose. If you'll give only minHeight parameter for eg. 300, the child will be of minimum height and will increase its size according to its content.

Here's an example:

ConstrainedBox(
   constraints: BoxConstraints(
       minHeight: 300,
       ),
   child: Container(child : SomeWidget(),)

If height required by SomeWidget() is less than 300, it will be of height 300. Otherwise, it will increase it's height accordingly. For decoration and structuring your SomeWidget(), you can use padding and other properties of Container.

Upvotes: 2

Firosh Vasudevan
Firosh Vasudevan

Reputation: 811

You can use deviceWidth and deviceHeight to check for min and max condition. Use the following code to get the deviceWidth and deviceHeight in build method.

double deviceWidth = MediaQuery.of(context).size.width;
double deviceHeight = MediaQuery.of(context).size.height;

In width and height property of Container use deviceWidth and deviceHeight to form your condition.

Container(
width: deviceWidth<200?50:deviceWidth*0.5,
height: deviceHeight<500?50:deviceHeight>800?200:deviceHeight*0.2,
child: //child,
)

Note: Only Ternary Operator ?: works for specifying condition for height and width

Upvotes: 3

Related Questions