Home > Software engineering >  Horizontal ListView doesn't show children with no fixed width
Horizontal ListView doesn't show children with no fixed width

Time:01-22

I'm trying to replicate this design: image

These 3 are progress indicators and their number is dynamic. That's why I thought of creating a list view and populating it depending on their number. Plus their size should NOT be fixed and they must, as a group, fill the size of the screen but this isn't happening.

Container(
                          height: 10,
                          width: 400,
                          child: ListView.builder(
                            physics: NeverScrollableScrollPhysics(),
                            scrollDirection: Axis.horizontal,
                            shrinkWrap: true,
                            itemCount: 3,
                            itemBuilder: (BuildContext context, int index) {
                              return Container(
                                child: LinearPercentIndicator(
                                    padding: index == 0 ? EdgeInsets.only(right: 4.0, left: 2.0) : EdgeInsets.symmetric(horizontal: 4.0),
                                    alignment: MainAxisAlignment.start,
                                    lineHeight: 5.0,
                                    percent: 1.0,
                                    progressColor: index == 2 ? theme.inboxListItemShadowColor : theme.userProfileTierBadgeColor,
                                    backgroundColor: theme.inboxListItemShadowColor,
                                    barRadius: Radius.circular(50)
                                ),
                              );
                            },
                          ),
                        )

And I thought this might create the design I needed but it always generates the error below:

RenderFlex children have non-zero flex but incoming width constraints are unbounded.

And that's because the Container widget containing the LinearPercentIndicator has no fixed width. And I don't want fixed width cause it won't support different screens.

So any idea on how I might do this? All i need is to have the children of the list view have dynamic widths depending on the screen and all fit in it.

Tried to give each container width like this:

width: (MediaQuery.of(context).size.width - 30) / n,

Where n is the number of progress indicators to create but it always messes up the design.

CodePudding user response:

The issue is LinearPercentIndicator is trying to get as much width as possible and horizontal ListView provides infinite width(you can think this way). You can provide fixed 1/3 screen width. for as for the ui, Row is enough.

Row(
  children: [
    for (int i = 0; i < 3; i  )
      Expanded(
        child: LinearPercentIndicator(
            padding: i == 0
                ? EdgeInsets.only(right: 4.0, left: 2.0)
                : EdgeInsets.symmetric(horizontal: 4.0),
            alignment: MainAxisAlignment.start,
            lineHeight: 5.0,
            percent: 1.0,
            barRadius: Radius.circular(50)),
      ),
  ],
),

Using fixed width

Container(
  height: 10,
  width: 400,
  child: ListView.builder(
    physics: NeverScrollableScrollPhysics(),
    scrollDirection: Axis.horizontal,
    shrinkWrap: true,
    itemCount: 3,
    itemBuilder: (BuildContext context, int index) {
      return Container(
        width: 400 / 3, //400 was your top widget width
        child: LinearPercentIndicator(
            padding: index == 0
                ? EdgeInsets.only(right: 4.0, left: 2.0)
                : EdgeInsets.symmetric(horizontal: 4.0),
            alignment: MainAxisAlignment.start,
            lineHeight: 5.0,
            percent: 1.0,
            barRadius: Radius.circular(50)),
      );
    },
  ),
)

CodePudding user response:

There is a very informative video about how ListViews try to take up space in your layout that I'd recommend watching: https://www.youtube.com/watch?v=jckqXR5CrPI

To summarize, ListViews will try to take up as much space as possible. In your case, when using scrollDirection: Axis.horizontal, the ListView will try to take up as much horizontal space as it can get.

Since you want the LinearProgressIndicators to have equal but dynamic sizes, I would recommend against using a ListView and instead use a Row with three Expanded widgets. A Row will only take up as much horizontal space as the screen will allow:

Row(
            children: const [
              Expanded(
                child: Padding(
                  padding: EdgeInsets.all(8.0),
                  child: LinearProgressIndicator(),
                ),
              ),
              Expanded(
                child: Padding(
                  padding: EdgeInsets.all(8.0),
                  child: LinearProgressIndicator(),
                ),
              ),
              Expanded(
                child: Padding(
                  padding: EdgeInsets.all(8.0),
                  child: LinearProgressIndicator(),
                ),
              ),
            ],
          ),
  • Related