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(),
),
),
],
),