Flutter - Alignment and Wrapping issues
Asked Answered
F

3

7

I'm trying to build a ListView, where the tiles look like this: enter image description here

However, I'm facing some issues here. So the item layout is

@override
Widget build(BuildContext context) {
  return new GestureDetector(
    onTap: _onTap,
    child: new Card(
      elevation: 1.0,
      color: Colors.white,
      margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 15.0),
      child: new Container(
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            new Container(
              margin: const EdgeInsets.only(right: 15.0),
              width: 100.0,
              height: 130.0,
              padding: const EdgeInsets.symmetric(
                  vertical: 10.0, horizontal: 5.0),
              decoration: new BoxDecoration(
                  shape: BoxShape.rectangle,
                  image: new DecorationImage(
                      fit: BoxFit.cover,
                      image: new NetworkImage(
                          "https://image.tmdb.org/t/p/w500" +
                              widget.movie.posterPath
                      )
                  )
              ),
            ),
            new Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                new Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    new Expanded(
                      flex: 0,
                      child: new Container(
                        margin: const EdgeInsets.only(
                            top: 12.0, bottom: 10.0),
                        child: new Text(widget.movie.title,
                          style: new TextStyle(
                            fontSize: 18.0,
                            color: Colors.black,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                    ),
                    new Expanded(
                      flex: 0,
                      child: new Text(
                        widget.movie.voteAverage.toString(),
                        style: new TextStyle(
                            fontSize: 16.0,
                            fontWeight: FontWeight.bold,
                            color: Colors.grey[600]
                        ),
                      ),
                    ),
                  ],
                ),
                new Container(
                  child: new Text(widget.movie.overview,
                    softWrap: true,
                    overflow: TextOverflow.ellipsis,
                    maxLines: 3,
                  ),
                ),
                new Container(
                  margin: const EdgeInsets.only(top: 5.0),
                  child: new Row(
                    children: <Widget>[
                      new Text("Released"),
                      new Container(
                          margin: const EdgeInsets.only(left: 5.0),
                          child: new Text(widget.movie.releaseDate)
                      ),
                    ],
                  ),
                ),
                new Container(
                  margin: const EdgeInsets.only(top: 5.0),
                  child: new Row(
                    children: <Widget>[
                      new Text("Rating"),
                      new Container(
                          margin: const EdgeInsets.only(left: 5.0),
                          child: new Text(widget.movie.voteAverage.toString())
                      ),
                    ],
                  ),
                ),
              ],
            )
          ],
        ),
      ),
    ),
  );
}

The layout hierarchy, as you can see in the image above, is

Row -> Image, Column -> (Row -> (Title, Rating)), Description, Text, Text

  1. First Issue

    The first issue is that I'm unable to align the Rating to the right within the Title, Rating row. So I want the title to be left aligned, and rating to be right aligned. For this, I tried to give a flex rating to both widgets, but as soon as I do that, both disappear. The only way I can think of is to give the Title a width, but that's a very hacky way and will break on most devices.

  2. Second Issue

    I want the Description to fit within the bounds of the Card. However, unless I define a specific width to the Container for Description, I'm unable to constrain it within the bounds of the screen. I tried encasing it within an Expanded, Flex and Flexible with various flex values, but no luck. I tried to use the softWrap property of Text widget, but again no luck. As soon as I wrap the Text in any of those widgets, it disappears. In the above code I've wrapped the Text in a Container, and set a width to it. This works, but again, it's very hacky, and will look different on different device, plus will break on a few.

Any help on these issues would be great.

Fiddlewood answered 11/5, 2018 at 3:47 Comment(0)
F
9

After a lot of trial and error, I finally managed to get what I wanted.

My layout is like this:

@override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: _onTap,
      child: new Card(
        elevation: 1.0,
        color: Colors.white,
        margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 14.0),
        child: new Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            new Container(
              margin: const EdgeInsets.only(right: 15.0),
              width: 100.0,
              height: 150.0,
              child: new Image.network(
                  "https://image.tmdb.org/t/p/w500" +
                      widget.movie.posterPath),
            ),
            new Expanded(
              child: new Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  new Row(
                    children: <Widget>[
                      new Expanded(
                        child: new Container(
                          margin: const EdgeInsets.only(
                              top: 12.0, bottom: 10.0),
                          child: new Text(widget.movie.title,
                            style: new TextStyle(
                              fontSize: 18.0,
                              color: Colors.black,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ),
                      ),
                      new Container(
                        margin: const EdgeInsets.only(right: 10.0),
                        child: new Text(
                          widget.movie.voteAverage.toString(),
                          style: new TextStyle(
                              fontSize: 16.0,
                              fontWeight: FontWeight.bold,
                              color: Colors.grey[600]
                          ),
                        ),
                      ),
                    ],
                  ),
                  new Container(
                    margin: const EdgeInsets.only(right: 10.0),
                    child: new Text(widget.movie.overview,
                      style: new TextStyle(
                        fontSize: 16.0,
                      ),
                      maxLines: 3,
                      overflow: TextOverflow.ellipsis,
                    ),
                  ),
                  new Container(
                    margin: const EdgeInsets.only(top: 10.0),
                    child: new Row(
                      children: <Widget>[
                        new Text("RELEASED",
                          style: new TextStyle(
                            color: Colors.grey[500],
                            fontSize: 11.0,
                          ),
                        ),
                        new Container(
                            margin: const EdgeInsets.only(left: 5.0),
                            child: new Text(widget.movie.releaseDate)
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

What I had to do was make the second child of my top level row an Expanded widget. So as you can see in the code, I put my column (after the image) within an Expanded.

The problem that was happening before was that Row has infinite bounds, so making my text expanded within a row's column was not making any difference to it. However, when I put the entire column into an expanded, it was bound by the screen width. That is what needs to be done.

The final output, with the above code, looks like this. enter image description here

Fiddlewood answered 11/5, 2018 at 19:29 Comment(0)
V
0

Here is the solution of your both the problem.

1) You just have to assign mainAxisAlighment.spaceBetween.

And you will good to go.

Below is the sample code which is solving your both the problems.

new Column(
          children: <Widget>[
            new Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                new Container(
                  margin: const EdgeInsets.only(
                      top: 12.0, bottom: 10.0, left: 10.0),
                  child: new Text(
                    "Avengers: Infinity war",
                    style: new TextStyle(
                      fontSize: 18.0,
                      color: Colors.black,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                new Container(
                  margin: const EdgeInsets.all(10.0),
                  child: new Text(
                    "8.6",
                    style: new TextStyle(
                        fontSize: 16.0,
                        fontWeight: FontWeight.bold,
                        color: Colors.grey[600]),
                  ),
                )
              ],
            ),
            new Container(
              margin: const EdgeInsets.only(left: 10.0, right: 10.0),
              child: new Text(
                "Iron Man, Thor, the Hulk and the rest of the Avengers unite to battle their most powerful enemy yet -- the evil Thanos. On a mission to collect all six Infinity Stones, Thanos plans to use the artifacts to inflict his twisted will on reality.",
                softWrap: true,
                maxLines: 3,
                overflow: TextOverflow.ellipsis,
              ),
            )
          ],
        )
Viewy answered 11/5, 2018 at 7:34 Comment(3)
Nope, this didn't help at all. It made the Title and Rating disappear and the description is still exceeding the bounds. I tried your exact code, replacing my column with yours - no luck..Fiddlewood
I'm starting to figure out the problem. The issue is because I'm putting a column within a row.. If I put a row within a row, your code works. Only in my particular case of column within a row with an image as the first element does this code not workFiddlewood
Thanks a lot, buddy. Your answer didn't actually work for me, but it did get me thinking in the right direction. When I realized that it was working without the top Row, that's when I kinda knew the solution.Fiddlewood
W
0

Just wrap your Wrap widget with an Expanded widget and it should work.

Worley answered 31/10, 2023 at 7:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.