Introduction to ListView in Flutter

4 min read, 15 August, 2018

ListView is a commonly used scrolling widget in Flutter. Children in ListView are displayed sequentially in the scrolling direction. In the other direction, the children need to fill the ListView. There are two main usage scenarios for ListView with different ListView constructors.

  • As a general-purpose layout widget - We only need the scrolling support to display widgets cannot fit in the current viewport. In this case, we should use the constructor ListView with a list of static children.
  • As a semantic widget for a list of items - We have a list of items to display. In this case, we should use the constructor ListView.builder with a function to build a widget for each item.

There is another constructor ListView.custom requires a SliverChildDelegate to provide the children. Actually, ListView and ListView.builder are both using ListView.custom with built-in subclasses of SliverChildDelegate, SliverChildListDelegate and SliverChildBuilderDelegate, respectively.

Use ListView

When using ListView, we only need to pass a List<Widget> containing all children to display in the ListView. All these children widgets will be created statically, even though some of them may not be currently visible in the viewport. You should not create a large number of children widgets when using ListView.

The function _generateItem below creates a new widget based on the index. Here I use the package logging to log out messages when this function is called.

Widget _generateItem(int index) {
  log.info('Generate item $index');
  return new Container(
    padding: const EdgeInsets.all(8.0),
    child: new Row(
      children: <Widget>[
        new Image.network(
          'http://via.placeholder.com/200x100?text=Item$index',
          width: 200.0,
          height: 100.0,
        ),
        new Expanded(child: new Text('Item $index'))
      ],
    ),
  );
}

StaticListView in the code below is a widget uses the ListView constructor. Here I generate 100 children widgets using the function _generate. When running the app, you should see the logging messages of creating all the 100 widgets.

List<Widget> _generate(int num) {
  return List.generate(num, (index) => _generateItem(index));
}

class StaticListView extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text('Static ListView')),
      body: new ListView(
        children: _generate(100),
      ),
    );
  }
}

ListView should be used for layouts that may need scrolling in some cases, for example, forms and dialogs. These kinds of layouts usually have a fixed number of widgets to display, and may need scrolling for small screens.

Use ListView.builder

When you have a list of items to display, it's better to use ListView.builder. The required parameter is a function itemBuilder of type IndexedWidgetBuilder with declaration Widget IndexedWidgetBuilder(BuildContext context, int index). Apart from the standard parameter BuildContext, the parameter index specifies the index of the current item to build. Another parameter itemCount of ListView.builder can specify the total number of items. The itemBuilder function will be called only with indices greater than or equal to 0 and less than itemCount.

DynamicListView in the code below uses ListView.builder to create a ListView. The itemCount is set to 100, while the itemBuilder function simply calls _generateItem. When running the app, you should see the logging messages of creating new children widgets when scrolling, which means children widgets are created dynamically when visible.

class DynamicListView extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text('Dynamic ListView')),
      body: new ListView.builder(
          itemCount: 100,
          itemBuilder: (BuildContext context, int index) =>
              _generateItem(index)),
    );
  }
}

If no itemCount is passed to ListView.builder, the itemBuilder function will be called when necessary to create a list with infinite number of items.

Below is the screenshot of ListView.

Screenshot of ListView

ListView.custom

ListView.custom is the third constructor to create ListView. It requires to provide an implementation of SliverChildDelegate. Generally, you don't need to subclass SliverChildDelegate directly. If you want to customise the behaviour of ListView, try to subclass SliverChildListDelegate and SliverChildBuilderDelegate instead.

Summary

This article shows the basic usage of ListView with the constructors ListView and ListView.builder. Use ListView for a fixed number of children widgets to enable scrolling. Use ListView.builder when you have a list of items that should be created dynamically.

Source code

Source code of this article is available on GitHub.