-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Description
Use case
This would be very useful for horizontal ListViews/SliverLists where the total height of the ListView is not known (or not easily known) but the height of each child in the ListView is known to be the same. See https://docs.flutter.dev/cookbook/lists/horizontal-list for an example of a horizontal scrollable list. This is used in many apps to show a small list (in terms of screen space taken) with a "Show More" button above that takes you to the full list on a dedicated page for that list. For example the IMBD app (gif)
By default, a ListView will take the entire available height unless constrained by a parent widget. The need for this functionality is documented by the following StackOverflow posts with a total of more than 100K views. (As well as my own personal need).
Horizontal ListView flutter WITHOUT explicit height
Flutter: Minimum height on horizontal list view
Most solutions involve shrinkwrap or abandoning Listview/CustomScrollView for a row of fixed children, both of which are bad for performance.
Proposal
From the docs:
SliverPrototypeExtentList class
A sliver that places its box children in a linear array and constrains them to have the same extent as a prototype item along the main axis.
Currently, SliverPrototypeExtentList will calculate the extent of the main axis (ie. widths) of the slivers in the Listview/SliverList using a provided prototype as a proxy. Calculating the cross axis as well (or instead) would provide a fixed constraint to the Listview/SliverList allowing it to be placed in a regular Column structure with the height calculated from the prototype.
Namely, adding a property like prototypeAxis: PrototypeAxis.crossAxis
Example:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const Text("Some static Text"),
CustomScrollView(
scrollDirection: Axis.horizontal,
slivers: <Widget>[
SliverPrototypeExtentList(
prototypeAxis: PrototypeAxis.crossAxis <--- proposed property, would be set to mainAxis by deafult. we can also have PrototypeAxis.all for both
prototypeItem:
Container(
color: Colors.red,
child: const Text('List Item Item 0'),
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
color: Colors.red,
child: Text('List Item Item $index'),
);
},
childCount: 20,
),
),
],
),
const Text("some text bellow")
]
)
);
}
}
It is already possible to mimic this behavior somewhat; from one of the posts:
PrototypeHeight(
prototype: MyItem(),
listView: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (_, index) => MyItem(),
),
)
class PrototypeHeight extends StatelessWidget {
final Widget prototype;
final ListView listView;
const PrototypeHeight({
Key? key,
required this.prototype,
required this.listView,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
IgnorePointer(
child: Opacity(
opacity: 0.0,
child: prototype,
),
),
SizedBox(width: double.infinity),
Positioned.fill(child: listView),
],
);
}
}
This is clearly a hack, however, and would have less performance than "first class" support for this feature. It would be nice for Flutter to support this use case directly, and it seems that it should be relatively straightforward given that similar functionality exists already in the form of SliverPrototypeExtentList
Note: this request is similar to #73786 except that request is more general in that it is asking for non-fixed height in a ListView where this request is about being able to provide a fixed height using a proposed extension to an existing widget. Although the requests are similar I feel that since the scope here is more limited and has a proposed solution it warrants a new ticket.