Skip to content

Add cross axis to SliverPrototypeExtentList  #120896

@yakagami

Description

@yakagami

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projectc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Flutterf: scrollingViewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions