skip to Main Content

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.

2

Answers


  1. 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)),
          );
        },
      ),
    )
    
    
    Login or Signup to reply.
  2. 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(),
                    ),
                  ),
                ],
              ),
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search