I'm trying to create a horizontal scrolling list of items in Flutter, and I want that list to only take up the necessary height based on its children. By design “ListView
tries to expand to fit the space available in its cross-direction” (from the Flutter docs), which I also notice in that it takes up the whole height of the viewport, but is there a way to make it not do this? Ideally something similar to this (which obviously doesn't work):
new ListView(
scrollDirection: Axis.horizontal,
crossAxisSize: CrossAxisSize.min,
children: <Widget>[
new ListItem(),
new ListItem(),
// ...
],
);
I realize that one way to do this is by wrapping the ListView
in a Container
with a fixed height. However, I don't necessarily know the height of the items:
new Container(
height: 97.0,
child: new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
new ListItem(),
new ListItem(),
// ...
],
),
);
I was able to hack together a “solution” by nesting a Row
in a SingleChildScrollView
in a Column
with a mainAxisSize: MainAxisSize.min
. However, this doesn't feel like a solution, to me:
new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: new Row(
children: <Widget>[
new ListItem(),
new ListItem(),
// ...
],
),
),
],
);
To limit the height of ListView, wrap the ListView with a Container widget and set the height of the Container to the required height.
To add 20 px: height + 20.0; To multiply just add a factor of your choice (can also be dynamic): height * 1.5 or height * dynamicFactor .
Since there's no height property in ListTile you can limit the size of a tile by placing it inside a SizedBox: SizedBox( height: 32, child: ListTile(..))
Just set shrink
property of ListView
to true
and it will fit the space rather than expanding.
Example:
ListView(
shrinkWrap: true, //just set this property
padding: const EdgeInsets.all(8.0),
children: listItems.toList(),
),
Use ConstrainedBox
to set minHeight
and maxHeight
ConstrainedBox(
constraints: new BoxConstraints(
minHeight: 35.0,
maxHeight: 160.0,
),
child: new ListView(
shrinkWrap: true,
children: <Widget>[
new ListItem(),
new ListItem(),
],
),
)
As far as I understand, you can't have a horizontal ListView inside a vertical ListView and have its height dynamically set. If your requirements allow (no infinite scrolling, small amount of elements, etc), you could use a SingleChildScrollView instead.
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [...],
),
);
Use a SingleChildScrollView
with scrollDirection: Axis.horizontal
and a Row
inside.
Big advantages:
It doesn't matter how many of widgets you need.
You don't need to know the heights of the widgets.
Widget _horizontalWrappedRow(List data) {
var list = <Widget>[SizedBox(width: 16)]; // 16 is start padding
//create a new row widget for each data element
data.forEach((element) {
list.add(MyRowItemWidget(element));
});
// add the list of widgets to the Row as children
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: list,
),
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With