4

I have two Container widgets in a Column, each containing a Text widget. I want the Container with the shortest text to expand to match the width of the other container containing the longer text. The container with the longer text should wrap the Text widget and its padding.

I can't get it to work without resorting to fixed widths on the containers:

return Column(
    mainAxisSize: MainAxisSize.min,
    children: [
        // This container has a shorter text than its sibling, so it should expand 
        // its width to match its sibling/parent
        Container(
            alignment: Alignment.center,
            width: 50, // I don't want this fixed width
            decoration: BoxDecoration(color: Colors.orange, borderRadius: BorderRadius.only(topLeft: Radius.circular(4), topRight: Radius.circular(4))),
            child: Padding(
                padding: const EdgeInsets.fromLTRB(8,4,8,4),
                child: Text('short'),
            )
        ),

        // This container has a longer text, so it should decide the width of the 
        // other container (and of the parent Column)
        Container(
            alignment: Alignment.center,
            width: 50, // I don't want this fixed width
            decoration: BoxDecoration(color: Colors.orange, borderRadius: BorderRadius.only(bottomLeft: Radius.circular(4), bottomRight: Radius.circular(4))),
            child: Padding(
                padding: const EdgeInsets.fromLTRB(8,4,8,4),
                child: Text('long text here'),
            )
        ),
    ]
);

I've tried a couple of ways to solve it involving Expanded and Flexible, but they all result in the "red screen of death" (or at least "annoyance").

EDIT

Just to be clear - I want the Column to just wrap its content, i.e. adjust its width to the width of the containers. In summary - everything should be as narrow as possible, except for the container with the shortest text, which should instead be as wide as its sibling (the container with the longer text).

Magnus
  • 17,157
  • 19
  • 104
  • 189
  • Expanded on one would lead to an out of bounds issue, so you gotta mark the other with flexible. But also, if you want to fill width, try using Rows on the containers. Something like Column -> (Row -> Container) , (Row -> Container) and then play however you like with the expansion you want. – ishaan Jun 17 '19 at 19:43

2 Answers2

7

I saw your Fiddle on a comment. And what you need is IntrinsicWidth.

  IntrinsicWidth(
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        // This container has a shorter text than its sibling, so it should expand
        // its width to match its sibling/parent
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 1.0),
          child: Container(
            color: Colors.orange,
            child: Padding(
              padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
              child: Text(
                'short',
                textAlign: TextAlign.center,
              ),
            ),
          ),
        ),

        // This container has a longer text, so it should decide the width of the
        // other container (and of the parent Column)
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 1.0),
          child: Container(
            color: Colors.orange,
            child: Padding(
              padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
              child: Text(
                'long text here',
                textAlign: TextAlign.center,
              ),
            ),
          ),
        ),
      ],
    ),
  ),

enter image description here

  • @MagnusW I've updated my answer based on your Fiddle. –  Jun 17 '19 at 21:55
  • Thanks, it's working! I tried to use this solution it in another situation as well (a `Column` with `FlatButton`'s, but in that case I had to combine this answer with the one by @Mariano Zorrilla in order to make it work, i.e. putting a `Wrap` Widget around the `IntrinsicWidth`. – Magnus Jun 18 '19 at 17:48
  • `crossAxisAlignment: CrossAxisAlignment.stretch`, is also a key part of the solution – w461 Sep 26 '20 at 13:25
1

You can use something like this to take the entire width of the Widget (make sure to be inside a MaterialApp and a Scaffold/Material child (home):

Wrap(
   children: <Widget>[
      Container(
           color: Colors.red,
           child: IntrinsicWidth(
                child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                   Container(
                     color: Colors.black,
                     height: 200,
                     child: Align(
                       alignment: Alignment.bottomRight,
                       child: Text(
                            "Hello World",
                            style: TextStyle(color: Colors.white),
                          ),
                        ),
                      ),
                   Container(
                     color: Colors.blue,
                     height: 100,
                     child: Align(
                     alignment: Alignment.topRight,
                          child: Text(
                            "Bottom Text Longer Text",
                            style: TextStyle(color: Colors.white),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          )

The Align is not necessary, is just to showcase how the width actually works with "double.infinity" and moving a text to the bottom right or top right portion of it.

Mariano Zorrilla
  • 7,165
  • 2
  • 34
  • 52
  • I can't get this to work - I'm guessing that this needs the parent of the `Column` to have a fixed width? I want the `Column` to wrap the containers and the containers to wrap the texts, but the container which has the text with the smallest width to match the width of the parent (i.e. the `Column`). – Magnus Jun 17 '19 at 20:14
  • Did you try to use a MaterialApp and a Scaffold as home value? You can use my logic for the body of the Scaffold. I just tested and it works. (or you could use a Material Widget instead of the Scaffold one). – Mariano Zorrilla Jun 17 '19 at 20:18
  • I tried it, but the width of the Column occupies the entire width of its parent, which is exactly what I'm trying to avoid - I want it to _wrap_ the Containers, i.e. shrink to fit. See [this jsfiddle](https://jsfiddle.net/e6bmqh27/6/) for an illustration of how I mean. – Magnus Jun 17 '19 at 21:05
  • @MagnusW check my updated response. Now that's what you need. You can even remove the Container with red background color (was just for testing). – Mariano Zorrilla Jun 17 '19 at 21:45