Flutter: ListView Widget – Complete Step-By-Step Guide

We use the ListView widget for showing items in rows or columns with the scroll. Here you will learn about what is a ListView widget, why you need them, and how you can create a static, dynamic (using builder) ListView which can scroll horizontally and vertically with some advanced tips.

What is a Flutter ListView?

ListView is a flutter widget that let your set of widgets appear in a scrollable list. The widgets are placed linearly one after another in the scroll direction. It makes a list of items scrollable.

ListView is basically a CustomeScrollView that has a single SliverList in its CustomScrollView.slivers property.

There are four types of list view constructors.

  1. ListView()
  2. ListView.builder()
  3. ListView.separated()
  4. ListView.custom()

You will explore each type of ListView (constructor) in-depth in this Flutter ListView tutorial guide.

Where we can use ListView?

ListView can be used anywhere you want to show a linear list of widgets with scroll functionality.

For example:

You have a settings page in your app where you want to show the settings tile in a vertical list. You can place the widget Vertically by using Column().

But,

You can’t scroll widgets inside the Column(). That’s why you have to use a ListView() widget to make the list items scrollable.

ListView Properties

ListView has 19 different types of properties that you can specify using above mentioned four types of named constructors (ListView(), ListView.builder(), ListView.separated, ListView.custom).

PropertyDescription
scrollDirectionYou can pass Axis.vertical or Axis.horizontal for scroll direction of your ListView widgets.
reverseDefault value is false but you can make it true. For reversing the order of the list.
controllerScrollController() that we can attach to the ListView() for controlling the scroll.
primaryYou can pass true or false and make ListView primary.
physicsYou can pass any ScrollPhysics() like:
AlwaysScrollableScrollPhysics()
BouncingScrollPhysics()
ClampingScrollPhysics()
FixedExtentScrollPhysics()
NeverScrollableScrollPhysics()
PageScrollPhysics()
RangeMaintainingScrollPhysics()
shrinkWrapListView usually take the whole space of the page. You can change that behavior by assigning true or false to this property.
paddingYou can pass EdgeInsets to add padding here.
itemExtentitemExtent is the area that widgets cover in the scroll direction. It is efficient to specify itemExtent because when scrolling the upcoming widget size is known by ListView through itemExtent property. You can pass double values that will take space in the horizontal or vertical direction according to the scroll direction.
prototypeItemJust like itemExtent, you can use prototypeItem to specify the extent or area covered by the children of the ListView widget. Here you will create a widget in which you specify the prototype format or structure of the actual child so that Flutter knows how much size this child item takes in ListView.
itemBuilderitemBuilder property is used inside the ListView.separated() and ListView.builder() constructors. This is used to create an on-demand ListView items widget.
itemBuilder gives us the context (BuildContext) and index (int). Here index is an int whose value is limited according to the value that you specify to the itemCount.(You specify your dart List variable-length most of the time.)
findChildIndexCallbackfindChildIndexCallback is used to find the index of child widgets by using keys. You can use it inside ListView.builder() and ListView.separated(). Check this Dartpad working example from this conversation.
itemCountitemCount is used inside the ListView.builder() or ListView.separated(). Here you define the length of the ListView by giving an integer value. This number limits the length of the ListView.
addAutomaticKeepAlivesYou can pass true or false in this property. Actually, you are telling the Flutter framework that wraps each child of ListView inside the AutomaticKeepAlive widget. By default addAutomaticKeepAlives value is true. But if you make it false it will garbage collected off-screen widgets and off-screen widgets will no longer stay alive even if they are lazy lists.
addRepaintBoundariesThe default value is true which is efficient most of the time because it creates a separate display list by wrapping it inside the RepaintBoundary. If you pass false to the addRepaintBoundries then it is only efficient if your use case is to repaint the children during scrolling.
addSemanticIndexesHere default value is also true. Basically, it warps children inside the IndexedSemantics which will give a semantic index to each element of the ListView so that the painted UI part has some meaning.
cacheExtentScrolling views have leading and trailing edges. You can specify cacheExtent or an area above and below the leading and trailing edges. If you give cacheExtent a double value then it will build the off-screen widgets that lie in that cache extent.
semanticChildCountYou can pass semanticChildCount int value to ListView() and ListView.builder(), ListView.custom() to specify the number of children that will contribute to the semantic information of the ListView().
dragStartBehaviorIt determines the way how drag will work when you start dragging inside the ListView.
The default value is DragStartBehavior.start and you can pass DragStartBehavior.down which makes your scrolling experience more reactive.
Add the dragStartBehavior property and check the app’s scrolling behavior.
keyboardDismissBehaviorIt takes ScrollViewKeyboardDismissBehavior enum manual or onDrag value. The default value is manual but if you change it to the onDrag then your keyboard will disappear when you drag down your ListView. For example, if you create TextField inside the ListView, when you tap on the TextField a keyboard will appear and when you scroll down the keyboard will disappear.
restorationIdRestorationManager restores the state of the Flutter app. restorationId takes String and persist its current scroll offset of ListView and restores it during state restoration.
clipBehaviorWe use clips to fasten something. Here you can pass Clip enum value. These can be :
Clip.antiAlias – smooth jagged edges when clipping the content.
Clip.antiAliasWithSaveLayer – while antiAlias clipping it also saveLayer immediately. Very slow and rarely used.
Clip.hardEdge – default value. Fast but slower then Clip.none. Clip content and don’t apply antiAlias (edge smoothing).
Clip.none – No performance cost. It will not clip the content.

Simple ListView in Flutter

ListView() widgets are used to create a simple ListView in Flutter. It is useful if you have a small number of elements (widgets). You can fully customize the ListView() widget but first, check its basic usage.

Basic Implementation of ListView()

ListView() has the children property which can hold the list of Widgets.

Here, you can use any widget for creating a list view.

ListView(
        children: const [
          widget,
          widget,
        ],
      ),

How to Create Simple ListView in Flutter?

In this Flutter example, you will create a simple ListView in Flutter.

Flutter Simple ListView Widget
Using Flutter Simple ListView

Here, you will use Text widget as the children of the ListView.

ListView(
        children: const [
          Text('🍇 Grapes', style: _style),
          Text('🍈 Melon', style: _style),
          Text('🍉 Watermelon', style: _style),
          Text('🍊 Tangerine', style: _style),
          Text('🍋 Lemon', style: _style),
          Text('🍌 Banana', style: _style),
          Text('🍍 Pineapple', style: _style),
          Text('🥭 Mango', style: _style),
          Text('🍎 Red Apple', style: _style),
          Text('🍏 Green Apple', style: _style),
          Text('🍇 Grapes', style: _style),
          Text('🍈 Melon', style: _style),
          Text('🍉 Watermelon', style: _style),
          Text('🍊 Tangerine', style: _style),
          Text('🍋 Lemon', style: _style),
          Text('🍌 Banana', style: _style),
          Text('🍍 Pineapple', style: _style),
          Text('🥭 Mango', style: _style),
          Text('🍎 Red Apple', style: _style),
          Text('🍏 Green Apple', style: _style),
        ],
      ),

const represents that the children of the ListView are constant.

const _style = TextStyle(fontSize: 50);

_style variable is used to increase the size of the ListView Text widget children.

Complete Widget Code:

import 'package:flutter/material.dart';

class ListViewTutorial extends StatelessWidget {
  const ListViewTutorial({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const _style = TextStyle(fontSize: 50);
    return Scaffold(
      appBar: AppBar(
        title: const Text('CodewithHussain'),
        centerTitle: true,
      ),
      body: ListView(
        children: const [
          Text('🍇 Grapes', style: _style),
          Text('🍈 Melon', style: _style),
          Text('🍉 Watermelon', style: _style),
          Text('🍊 Tangerine', style: _style),
          Text('🍋 Lemon', style: _style),
          Text('🍌 Banana', style: _style),
          Text('🍍 Pineapple', style: _style),
          Text('🥭 Mango', style: _style),
          Text('🍎 Red Apple', style: _style),
          Text('🍏 Green Apple', style: _style),
          Text('🍇 Grapes', style: _style),
          Text('🍈 Melon', style: _style),
          Text('🍉 Watermelon', style: _style),
          Text('🍊 Tangerine', style: _style),
          Text('🍋 Lemon', style: _style),
          Text('🍌 Banana', style: _style),
          Text('🍍 Pineapple', style: _style),
          Text('🥭 Mango', style: _style),
          Text('🍎 Red Apple', style: _style),
          Text('🍏 Green Apple', style: _style),
        ],
      ),
    );
  }
}

How to Use ListView.builder() in Flutter?

For creating ListView using builder parameters we use ListView.builder. This method of creating ListView is performance friendly because it creates ListView children’s widgets lazily.

First, let’s create a dart text list and call it fruits.

List<String> fruits = [
  '🍇 Grapes',
  '🍈 Melon',
  '🍉 Watermelon',
  '🍊 Tangerine',
  '🍋 Lemon',
  '🍌 Banana',
  '🍍 Pineapple',
  '🥭 Mango',
  '🍎 Red Apple',
  '🍏 Green Apple',
  '🍐 Pear',
  '🍑 Peach',
  '🍒 Cherries',
  '🍓 Strawberry',
  '🫐 Blueberries',
  '🥝 Kiwi Fruit',
  '🍅 Tomato',
  '🫒 Olive',
];

Now, create a ListView.builder()

ListView.builder(
            itemCount: fruits.length,
            itemBuilder: (context, index) {
              
             //Here you define the widget and return it
 })

You are using itemCount and itemBuilder for creating a list view.

itemCount: takes the int value and here we are giving the length of the list of the fruits.

itemBuilder: takes an anonymous function that receives context (BuildContext) and index (int) from the framework. That we can use to create each widget that ListView builds.

Create Widget for ListView.builder()

final item = Text(fruits[index], style: _style);
return item;

Here, you create a Text widget and assign it to the item variable. Inside the Text widget, you take a single value from the list of fruits for each ListView widget.

Here

index variable has incremental values from a 0 index to the fruits.length (number of elements that the fruit list has).

That’s how builder loop through each value of the list of the fruits and create a Text widget that is shown by the ListView.

_style is the style of the Text.

const _style = TextStyle(fontSize: 50);

Note: return widget inside the anonymous function.

Complete ListView.builder() Widget Code:

import 'package:flutter/material.dart';

class ListViewTutorial extends StatelessWidget {
  const ListViewTutorial({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const _style = TextStyle(fontSize: 50);
    return Scaffold(
        appBar: AppBar(
          title: const Text('CodewithHussain'),
          centerTitle: true,
        ),
        body: ListView.builder(
            itemCount: fruits.length,
            itemBuilder: (context, index) {
              final item = Text(fruits[index], style: _style);
              return item;
            })
        );
  }
}

List<String> fruits = [
  '🍇 Grapes',
  '🍈 Melon',
  '🍉 Watermelon',
  '🍊 Tangerine',
  '🍋 Lemon',
  '🍌 Banana',
  '🍍 Pineapple',
  '🥭 Mango',
  '🍎 Red Apple',
  '🍏 Green Apple',
  '🍐 Pear',
  '🍑 Peach',
  '🍒 Cherries',
  '🍓 Strawberry',
  '🫐 Blueberries',
  '🥝 Kiwi Fruit',
  '🍅 Tomato',
  '🫒 Olive',
];

How to User ListView.separated() in Flutter?

ListView.separated is also used builder method for creating ListView. Like Listview.builder, it also builds each element widget using index.

But,

You can specify separatorBuilder inside ListView.separated. separatorBuilder is used to add any kind of separator widget, here in this example we add a Divider widget as a separator.

Flutter List View with Divider. How to User ListView.separated() in Flutter?
List View with Divider

You can see the purple divider line. You can create this line by using Divider widget.

const Divider(
  thickness: 3,
  color: Colors.purple,
);

Now let’s see how you can create this list view with a divider line.

Basic Implementation of ListView.separated()

These are the basic things that you need to add to create ListView.separated().

ListView.separated(
          itemCount: //length of the list,
          itemBuilder: (context, index) {
            //each individual widget that we build in list
          },
          separatorBuilder: (context, index) {
            //Separator that is used to add line
          },
        )

ListView.separated() Example

Here you will also create a list of strings.

List<String> fruits = [
  '🍇 Grapes',
  '🍈 Melon',
  '🍉 Watermelon',
  '🍊 Tangerine',
  '🍋 Lemon',
  '🍌 Banana',
  '🍍 Pineapple',
  '🥭 Mango',
  '🍎 Red Apple',
  '🍏 Green Apple',
  '🍐 Pear',
  '🍑 Peach',
  '🍒 Cherries',
  '🍓 Strawberry',
  '🫐 Blueberries',
  '🥝 Kiwi Fruit',
  '🍅 Tomato',
  '🫒 Olive',
];

Then you will have the ListViewTutorial widget which has Scaffold that represents the screen.

class ListViewTutorial extends StatelessWidget {
  const ListViewTutorial({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const _style = TextStyle(fontSize: 50);
    return Scaffold(
        appBar: AppBar(
          title: const Text('CodewithHussain'),
          centerTitle: true,
        ),
        body: //Here you specify the List
  }
}

You create the screen, where inside the build method you define the _style which will increase the size of each child of the list view.

Then you create AppBar for the app.

Inside the body, you will create the list view which has a separator.

ListView.separated(
          itemCount: fruits.length,
          itemBuilder: (context, index) {
            final item = Text(fruits[index], style: _style);
            return item;
          },
          separatorBuilder: (context, index) {
            return const Divider(
              thickness: 3,
              color: Colors.purple,
            );
          },
        )
      );

ListView.separated will take the itemCount, itemBuilder, and separatorBuilder.

PropertyDescription
itemCountYou assign (fruits.length) which is the length of the list of fruits that we have created before.
itemBuilderHere you pass an anonymous function that receives the context and index that you receive to produce the Text widget and return that widget.
separatorBuilderHere you use the above define Divider widget and return it. You can use it to insert ads inside the ListView.
ListView.separated() widget properties

Complete Example Code:

import 'package:flutter/material.dart';

class ListViewTutorial extends StatelessWidget {
  const ListViewTutorial({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const _style = TextStyle(fontSize: 50);
    return Scaffold(
        appBar: AppBar(
          title: const Text('CodewithHussain'),
          centerTitle: true,
        ),
        body: ListView.separated(
          itemCount: fruits.length,
          itemBuilder: (context, index) {
            final item = Text(fruits[index], style: _style);
            return item;
          },
          separatorBuilder: (context, index) {
            return const Divider(
              thickness: 3,
              color: Colors.purple,
            );
          },
        )
      );
  }
}
List<String> fruits = [
  '🍇 Grapes',
  '🍈 Melon',
  '🍉 Watermelon',
  '🍊 Tangerine',
  '🍋 Lemon',
  '🍌 Banana',
  '🍍 Pineapple',
  '🥭 Mango',
  '🍎 Red Apple',
  '🍏 Green Apple',
  '🍐 Pear',
  '🍑 Peach',
  '🍒 Cherries',
  '🍓 Strawberry',
  '🫐 Blueberries',
  '🥝 Kiwi Fruit',
  '🍅 Tomato',
  '🫒 Olive',
];

How to use ListView.custom() in Flutter?

It’s time to see ListView.custom which you can use to customize the list view by adding custom functionality.

Let’s see its basic implementation.

Basic Implementation of ListView.custom()

Here childrenDelegate is a required property. And of course, you can pass the length of the list inside the childCount.

ListView.custom(   
        childrenDelegate: // Here you pass SliverChildDelegate,
          childCount: //length of the List,
        ),
 

childrenDelegate will take SliverChildDelegate which is an abstract type. There are two implementors SliverChildDelegate that you can pass to the childrenDelegate property.

  1. SliverChildBuilderDelegate
  2. SliverChildListDelegate

ListView.custom() with SliverChildBuilderDelegate Example

In this example of ListView.custom() you will use SliverChildBuilderDelegate to produce children for a list view which is a sliver list.

If you have a question what is the difference between ListView and SliverList?

The short answer is: there is no difference.

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class ListViewTutorial extends StatelessWidget {
  const ListViewTutorial({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const _style = TextStyle(fontSize: 50);
    return Scaffold(
      appBar: AppBar(
        title: const Text('CodewithHussain'),
        centerTitle: true,
      ),
      body: ListView.custom(
        childrenDelegate: SliverChildBuilderDelegate(
          (BuildContext context, index) {
            final item = Text(fruits[index], style: _style);
            return item;
          },
          childCount: fruits.length,
        ),
      ),
    );
  }
}

List<String> fruits = [
  '🍇 Grapes',
  '🍈 Melon',
  '🍉 Watermelon',
  '🍊 Tangerine',
  '🍋 Lemon',
  '🍌 Banana',
  '🍍 Pineapple',
  '🥭 Mango',
  '🍎 Red Apple',
  '🍏 Green Apple',
  '🍐 Pear',
  '🍑 Peach',
  '🍒 Cherries',
  '🍓 Strawberry',
  '🫐 Blueberries',
  '🥝 Kiwi Fruit',
  '🍅 Tomato',
  '🫒 Olive',
];

Preview:

ListView.custom() with SliverChildBuilderDelegate Example

Horizontal ListView VS Vertical ListView

You can create list views horizontally and vertically.

  • Horizontal ListView
  • Vertical ListView

How to create Horizontal ListView?

You can create a horizontal list view by passing the scrollDirection value to Axis.horizontal. This will convert the Vertical ListView to the Horizontal ListView.

Example Complete Code

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class ListViewTutorial extends StatelessWidget {
  const ListViewTutorial({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const _style = TextStyle(fontSize: 50);
    return Scaffold(
      appBar: AppBar(
        title: const Text('CodewithHussain'),
        centerTitle: true,
      ),
      body:ListView(
        scrollDirection: Axis.horizontal,
        children: const [
          Text('🍇 Grapes', style: _style),
          Text('🍈 Melon', style: _style),
          Text('🍉 Watermelon', style: _style),
          Text('🍊 Tangerine', style: _style),
          Text('🍋 Lemon', style: _style),
          Text('🍌 Banana', style: _style),
          Text('🍍 Pineapple', style: _style),
          Text('🥭 Mango', style: _style),
          Text('🍎 Red Apple', style: _style),
          Text('🍏 Green Apple', style: _style),
          Text('🍇 Grapes', style: _style),
          Text('🍈 Melon', style: _style),
          Text('🍉 Watermelon', style: _style),
          Text('🍊 Tangerine', style: _style),
          Text('🍋 Lemon', style: _style),
          Text('🍌 Banana', style: _style),
          Text('🍍 Pineapple', style: _style),
          Text('🥭 Mango', style: _style),
          Text('🍎 Red Apple', style: _style),
          Text('🍏 Green Apple', style: _style),
        ],
      ),
    );
  }
}

Preview:

Flutter horizontal ListView

How to create a Vertical ListView?

By default, Flutter creates ListView in the vertical direction because the default scrollDirection value is Axis.vertical.

You can explicitly specify this value by giving scrollDirection an Axis.vertical value.

Example Code:

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class ListViewTutorial extends StatelessWidget {
  const ListViewTutorial({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const _style = TextStyle(fontSize: 50);
    return Scaffold(
      appBar: AppBar(
        title: const Text('CodewithHussain'),
        centerTitle: true,
      ),
      body: ListView(
        scrollDirection: Axis.vertical,
        children: const [
          Text('🍇 Grapes', style: _style),
          Text('🍈 Melon', style: _style),
          Text('🍉 Watermelon', style: _style),
          Text('🍊 Tangerine', style: _style),
          Text('🍋 Lemon', style: _style),
          Text('🍌 Banana', style: _style),
          Text('🍍 Pineapple', style: _style),
          Text('🥭 Mango', style: _style),
          Text('🍎 Red Apple', style: _style),
          Text('🍏 Green Apple', style: _style),
          Text('🍇 Grapes', style: _style),
          Text('🍈 Melon', style: _style),
          Text('🍉 Watermelon', style: _style),
          Text('🍊 Tangerine', style: _style),
          Text('🍋 Lemon', style: _style),
          Text('🍌 Banana', style: _style),
          Text('🍍 Pineapple', style: _style),
          Text('🥭 Mango', style: _style),
          Text('🍎 Red Apple', style: _style),
          Text('🍏 Green Apple', style: _style),
        ],
      ),
    );
  }
}

Preview:

Flutter Vertical ListVIew

Conclusion:

You learn how you can use Flutter ListView() widget. You also learn about ListView.builder(), ListView.separated() and ListView.custom() in detail with examples. Also, you explored some tips and basic use cases of Flutter ListView.

You can find more:

Hope you like this Flutter tutorial. Thanks!

Hussain Humdani

Hussain Humdani

while ( ! ( succeed = try() ) );