Flutter Layout Row / Column - share width, expand height
Asked Answered
G

5

125

I'm still having a bit of trouble with the layouting in Flutter.
Right now I want to have the available space shared between 3 widgets, in a quadrant layout. The width is evenly shared (this works fine via 2 Expanded widgets in a Row), but now I also want the height to adjust automatically so widget3.height == widget1.height + widget2.height. layout If the content of widget3 is larger, I want widget1 and widget2 to adjust their height and vice versa.

Is this even possible in Flutter?

Granado answered 13/7, 2018 at 13:23 Comment(0)
I
375

Have a look at IntrinsicHeight; wrapping the root Row should provide the effect you're looking for:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(title: Text('Rows & Columns')),
        body: RowsAndColumns(),
      ),
    );
  }
}

class RowsAndColumns extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 100.0),
      child: IntrinsicHeight(
        child: Row(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
          Expanded(
            child: Column(children: [
              Container(height: 120.0, color: Colors.yellow),
              Container(height: 100.0, color: Colors.cyan),
            ]),
          ),
          Expanded(child: Container(color: Colors.amber)),
        ]),
      ),
    );
  }
}

Adjusting the heights in the containers in the column cause the container on the right to resize to match:

screenshot

https://gist.github.com/mjohnsullivan/c5b661d7b3b4ca00599e8ef87ff6ac61

Illomened answered 13/7, 2018 at 17:24 Comment(9)
Are you sure there isn'y any other way to do this? Because in the official documentation, it says not to use this Widget because it is too expensive.Huge
Note from the flutter docs on IntrinsicHeight: This class is relatively expensive. Avoid using it where possible.Civilization
It's expensive but I don't think flutter provides any other way that is better and faster.Crenellate
Is it ok to use it inside a list? @matt-sUnpopular
@Unpopular tested inside a list and it works perfectly!Sisal
Is it cheaper to call WidgetsBinding.addPostFrameCallback(() {}), measure widget height and set it to the other widget?Contingency
The Row's crossAxisAlignment: CrossAxisAlignment.stretch should be emphasized for this to work.Crenellate
How can I put a ListView inside the container with Amber color? If I place ListView there everything disappears.Bananas
There is a way to avoid IntrinsicHeight by using Table and TableCell with verticalAlignment: TableCellVerticalAlignment.fill. Added the answer below, hope it helps!Polley
P
12

Since IntrinsicHeight is considered relatively expensive, it's better to avoid it. You can use Table with verticalAlignment: TableCellVerticalAlignment.fill in the largest TableCell.

Please note that if you use .fill in all cells, the TableRow will have zero height.

  Table(children: [
    TableRow(children: [
      Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Container(
            alignment: Alignment.center,
            color: Colors.blue,
            child: Text('Widget 1'),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.green,
            child: Text('Widget 2'),
          ),
        ],
      ),
      TableCell(
          verticalAlignment: TableCellVerticalAlignment.fill,
          child: Container(
            alignment: Alignment.center,
            color: Colors.orange,
            child: Text('Widget 3'),
          )),
    ]),
  ]),
Polley answered 21/1, 2022 at 21:54 Comment(0)
L
10

I think that you can set the height of the row instead, then you only must to set the height of you column containers, and with the crossAxisAlignment: CrossAxisAlignment.stretch the second row will be expand occupying his parent height:

Row(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: [
    Expanded(
      child: Column(
        children: [
          Expanded(
            // If you don't have the height you can expanded with flex
            flex: 1,
            child: Container(
              height: 50,
              color: Colors.blue,
            ),
          ),
          Expanded(
            flex: 1,
            child: Container(
              height: 50,
              color: Colors.red,
            ),
          )
        ],
      ),
    ),
    Expanded(
      child: Container(
        color: Colors.yellow,
      ),
    )
  ],
)
Leix answered 12/1, 2022 at 14:32 Comment(2)
This solution is neat, I kinda prefer itIrenics
Doesn't work in my case. I get BoxConstraints forces an infinite height. error.Crenellate
C
1

I'm new to flutter. Please correct me if I'm doing something wrong here. I think It can also be achieved using setState((){}) without using IntrinsicHeight.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MyAppState();
  }
}

class MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    double h1 = 100;
    double h2 = 200;
    double h3;
    setState(() {
      h3 = h1 + h2;
    });
    return MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Padding(
            padding: const EdgeInsets.only(top: 100.0),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                  child: Column(
                    children: [
                      Container(
                        color: Colors.green,
                        height: h1,
                      ),
                      Container(
                        color: Colors.orange,
                        height: h2,
                      )
                    ],
                  ),
                ),
                Expanded(
                  child: Container(
                    color: Colors.yellow,
                    height: h3,
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Find image here

Code can also be found here: https://gist.github.com/Amrit0786/9d228017c2df6cf277fbbaa4a6b20e83

Calore answered 19/8, 2020 at 13:28 Comment(2)
If you have a big app, you would wanna limit the StatefulWidget as much as possible. Alternatively, use StatelessWidget with built-in solution. Using Stateful for layout is not technically wrong, but you should not use it unless you have no other option.Cilicia
am trying to understand why u use setstate in build ??!! wow....!Adminicle
K
-1

if you have used the expanded inside Row and facing for full height issue then just wrap the expanded child with Align widget.

Kiosk answered 4/11, 2022 at 13:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.