Flutter ListView Tutorial and Examples.

In this tutorial we want to look at one of the most important widgets especially when it comes to rendering lists of data, the ListView.

What is a ListView?

A ListView is a scrollable list of widgets arranged linearly.

As the names suggests it's responsibility is list items. These items can then scrolled. ListView isn't the only scrolling view. There are others like gridview, however ListView is the most commonly used.

ListView will display its children one after another in the scroll direction. In the cross axis, the children are required to fill the ListView.

Here's a simple infinite listview:

new ListView.builder(
  padding: new EdgeInsets.all(8.0),
  itemExtent: 20.0,
  itemBuilder: (BuildContext context, int index) {
    return new Text('entry $index');
  },
)

More ListView documentation can be found here.

Let's look a flutter ListView example with onClick.

Why ListView?

Well ListViews are probably the most commonly used widgets for displaying lists of data. In most cases we use it together with CardViews. And in fact render images and text. You may have already seen countless apps with lists of images and text.

If it is flutter application, then chances are that either gridview or listview has been used.

ListViews and GridViews are important because given the nature(small screen) of mobile devices, you always need to have the ability to scroll through data. The screen can only display a small of data per viewport. So we need a component that can easily be scrolled.

Also the fact that most of mobile apps by their nature require the ability to show lists of data. Mobile apps are not mostly used for heavy data entry like Microsoft Word, Excel etc in PC. Rather majority of apps require us to fetch data from the server and render to the user. These types of apps need widgets like ListViews.

Flutter Examples

Let us now look at some full examples.

Section 1: Basic ListViews

Let's start by looking at really simple and basic listviews to introduce you to ListView creation. The examples in this section only contain one single file so you can easily copy to your project. They also don't require any special depdency or configuration.

Example 1: Flutter Simple ListView with OnClick Example

This is a simple flutter listview example to display items from a flutter fixed-length list, otherwise known as an array in other languages. Obviously we write our app in Dart programming language.

Here is the demo:

Flutter ListView Example

If the user clicks a single cardview, a CupertinoAlertDialog will be rendered with the clicked item.

The dialog will have some text and icon.

And here's our video tutorial:

Here are the files we explore:

  1. pubspec.yaml
  2. lib/main.dart

Step 1: pubspec.yaml

No external dependency is needed:

name: simple_listview
description: A Simple ListView Flutter application.

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter
flutter:
  uses-material-design: true

Step 2: main.dart

This is where we write our flutter code in dart programming language. In Dart it is very common to write several classes in a single file. So this simple file will have three classes.

Importing Packages in Flutter/Dart

But first we need to import some packages and we do that using the import keyword in dart.

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

Here are the packages we are importing:

  1. material.dart : will give us material design widgets and theme.
  2. cupertino.dart : Will give us CupertinoAlertDialog as well as cupertino icons.

Creating classes in Flutter/Dart

In Dart like in most C style programming languages you create a class using the class keyword. Classes are encapsulation mechanism in Object Oriented Programming languages.

In this case we create three classes:
1.class MyApp extends StatelessWidget {..}

  1. class Home extends StatefulWidget {..}
  2. class _HomeState extends State<Home> {..}

Our first class is deriving from StatelessWidget and implementing the build() method. That method will build a materialapp widget with title, home and theme set and return it as a widget.

The second class will derive from StatefulWidget and override the createState() method.

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter ListView',
      home: new Home(),
      theme: new ThemeData(primaryColor: Colors.orange),
    );
  }
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => new _HomeState();
}

class _HomeState extends State<Home> {

  @override
  Widget build(BuildContext context) {
    var spacecrafts = ["James Web","Enterprise","Hubble","Kepler","Juno","Casini","Columbia","Challenger","Huygens","Galileo","Apollo","Spitzer","WMAP","Swift","Atlantis"];
    var listItem = new ListView.builder(
      itemCount: spacecrafts.length,
      itemBuilder: (BuildContext context, int index) {
        return new ListTile(
          title: new Card(
            elevation: 5.0,
            child: new Container(
              alignment: Alignment.centerLeft,
              margin: new EdgeInsets.only(top: 10.0, bottom: 10.0),
              child: new Text(spacecrafts[index]),
            ),
          ),
          onTap: () {
            showDialog(
                barrierDismissible: false,
                context: context,
                child: new CupertinoAlertDialog(
                  title: new Column(
                    children: <Widget>[
                      new Text("ListView"),
                      new Icon(
                        Icons.favorite,
                        color: Colors.red,
                      ),
                    ],
                  ),
                  content: new Text( spacecrafts[index]),
                  actions: <Widget>[
                    new FlatButton(
                        onPressed: () {
                          Navigator.of(context).pop();
                        },
                        child: new Text("OK"))
                  ],
                ));
          },
        );
      },
    );

    return new Scaffold(
      appBar: new AppBar(
          title: new Text("Flutter ListView")
      ),
      body: listItem,
    );
  }
}
void main() {
  runApp(new MyApp());
}

Flutter ListView with Images and text

Let's look at a simple example to render images/icons and text in a ListView in ListTiles. This is a very basic example.

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build (BuildContext context){
    final title = 'Basic List';
    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: ListView(
          children: <Widget>[
            ListTile(
              title: Text('Map'),
              leading: Icon(Icons.map),
            ),
            ListTile(
              title: Text('Photo Album'),
              leading: Icon(Icons.photo_album),
            ),
            ListTile(
              title: Text('Phone'),
              leading: Icon(Icons.phone),
            ),
          ],)
      )
    );
  }
}

Conclusion

Simply copy the code into your main.dart file. It is only a single file. We've looked at how to implement a simple listview with cardviews. When the user clicks a cardview we open a curperdino dialog.

Let us now look at other examples in the next sections.


Example 2: ListView TextFields

This is yet another simple Listview example. In this example we will look at how to render TextFields in a Listview.

Here is the demo of what is created:

ListView TextFields

Step 1: Create Project

Start by creating an empty Flutter project.

Step 2: Dependencies

No special dependency is needed for this project.

Step 3: Write Code

We will be buiding several custom widgets. For example here is how we build a card widget:

    Widget card = Center(
      child: Card(
        color: Colors.white,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Padding(
                padding:
                  const EdgeInsets.fromLTRB(12.0, 24.0, 50.0, 12.0),
                child: const ListTile(
              leading: Icon(
                Icons.account_balance_wallet,
                color: Colors.redAccent,
                size: 50.0,),
              title: Text(
                  '€ 54.08',
                  style: TextStyle(
                    fontSize: 40.0, fontWeight: FontWeight.bold
                  ),
                  textAlign: TextAlign.center,
                ),
              subtitle: Text(
                'EUR · Euro',
                style: TextStyle(
                  fontSize: 20.0,
                  fontWeight: FontWeight.bold
                ),
                textAlign: TextAlign.center,
              ),
            ),
        ),
          ],
        ),
      ),
    );

Here is how we build our button section:

    Widget buttonSection = Container(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          buildButtonColumn(Icons.call, 'CALL'),
          buildButtonColumn(Icons.near_me, 'ROUTE'),
          buildButtonColumn(Icons.share, 'SHARE')
        ],
      ),
    );

Here is the full code:

main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: new ListDisplay(),
    );
  }
}

class ListDisplay extends StatefulWidget {
  _ListDisplayState createState() => _ListDisplayState();
}

class Tx {
  String type;
  double amount;
  DateTime dateTime;

  Tx(this.type, this.amount, this.dateTime);
}

class TxList {
  DateTime dateTime;
  Tx tx;

  TxList(this.dateTime, this.tx);
}

class _ListDisplayState extends State<ListDisplay> {

  List<String> listItems = ["first", "second", "the quick brown fox", "jumps over", "the lazy dog!"];

  final List<Tx> txns = new List<Tx>();
  final List<TxList> txnLists = new List<TxList>();

  var dateTimeFormatter = new DateFormat('yyyy-MM-dd H:m:s');
  var dateFormatter = new DateFormat('yyyy-MM-dd');
  //print(new DateFormat.yMMMMEEEEd().format(new DateTime.now()));

  @override
  void initState() {
    super.initState();
    setState(() {
      txns.add(new Tx("Transfer to A", 20.0, DateTime.now()));
      txns.add(new Tx("Transfer to B", -10.0, DateTime.now()));
      txns.add(new Tx("Transfer to C", 200.0, DateTime.now()));
      txns.add(new Tx("Transfer to D", -50.0, DateTime.now()));
      txns.add(new Tx("Transfer to E", -24.0, DateTime.now()));
      txns.add(new Tx("Transfer to F", 190.0, DateTime.now()));

      //new list
      txnLists.add(new TxList(DateTime.now(), new Tx("Transfer to A", 20.0, DateTime.now())));
      txnLists.add(new TxList(DateTime.now(), new Tx("Transfer to B", -10.0, DateTime.now())));
      txnLists.add(new TxList(DateTime.now(), new Tx("Transfer to C", 200.0, DateTime.now())));
      txnLists.add(new TxList(DateTime.now(), new Tx("Transfer to D", -50.0, DateTime.now())));
      txnLists.add(new TxList(DateTime.now(), new Tx("Transfer to E", -24.0, DateTime.now())));
      txnLists.add(new TxList(DateTime.now(), new Tx("Transfer to F", 190.0, DateTime.now())));
    });
  }

  final TextEditingController textEditingController = new TextEditingController();
  @override
  Widget build(BuildContext context) {

    Widget buildBody(BuildContext context, int index) {
      return Card(
          child: Text(listItems[index]),
        );
    }

    Widget titleSection = Container(
      padding: const EdgeInsets.all(32.0),
      child: Row(
        children: <Widget>[
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Container(
                  padding: EdgeInsets.only(bottom: 8.0),
                  child: Text(
                    'Oeschinen Lake Campground',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                    ),
                  )
                ),
                Text(
                  'Kandersteg, Switzerland',
                  style: TextStyle(
                    color: Colors.grey[500],
                  ),
                ),
              ]
          )
          ),
          Icon(
            Icons.star,
            color: Colors.red[500],
            ),
          Text('41'),
      ],)
    );

    Column buildButtonColumn(IconData icon, String label) {

      Color color = Theme.of(context).primaryColor;

      return Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Icon(icon, color: color),
          Container(
            margin: EdgeInsets.only(top: 8.0),
            child: Text(
              label,
              style: TextStyle(
                fontSize: 12.0,
                fontWeight: FontWeight.w400,
                color: color,
              ),
              ),
          ),
        ],
      );
    }

    Widget buttonSection = Container(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          buildButtonColumn(Icons.call, 'CALL'),
          buildButtonColumn(Icons.near_me, 'ROUTE'),
          buildButtonColumn(Icons.share, 'SHARE')
        ],
      ),
    );

    Widget textSection = Container(
      padding: EdgeInsets.all(32.0),
      child: Text(
        '''
        Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, followed by a half-hour walk through pastures and pine forest, leads you to the lake, which warms to 20 degrees Celsius in the summer. Activities enjoyed here include rowing, and riding the summer toboggan run.
        ''',
        softWrap: true,
      ),
    );

    Widget gridView = new Expanded(
        child: GridView.builder(
          itemBuilder: (context, position) {
            return Card(
              child: Text(listItems[position]),
            );
          },
          itemCount: listItems.length,
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4),
        )
      );

    Widget card = Center(
      child: Card(
        color: Colors.white,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Padding(
                padding:
                  const EdgeInsets.fromLTRB(12.0, 24.0, 50.0, 12.0),
                child: const ListTile(
              leading: Icon(
                Icons.account_balance_wallet,
                color: Colors.redAccent,
                size: 50.0,),
              title: Text(
                  '€ 54.08',
                  style: TextStyle(
                    fontSize: 40.0, fontWeight: FontWeight.bold
                  ),
                  textAlign: TextAlign.center,
                ),
              subtitle: Text(
                'EUR · Euro',
                style: TextStyle(
                  fontSize: 20.0,
                  fontWeight: FontWeight.bold
                ),
                textAlign: TextAlign.center,
              ),
            ),
        ),
          ],
        ),
      ),
    );

    Widget emailView = ListView.builder(
      itemCount: listItems.length,
      itemBuilder: (context, position) {

        Tx txn = txns[position];
        TxList txnList = txnLists[position];

        return Column(
          children: <Widget>[

            // ListTile(
            //     title: Text(
            //       dateFormatter.format(txnList.dateTime),
            //       style: Theme.of(context).textTheme.headline,
            //     ),
            // ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Column(
                    //mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      // Text(
                      //   "5m",
                      //   style: TextStyle(color: Colors.grey),
                      // ),
                       Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Icon(
                          Icons.credit_card,
                          size: 35.0,
                          color: Colors.grey,
                        ),
                      ),
                    ],
                  ),
                ),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Padding(
                      padding:const EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 6.0),
                      child: Text(
                        txn.type,
                        style: TextStyle(
                            fontSize: 22.0, fontWeight: FontWeight.bold),
                      ),
                    ),
                    Padding(
                      padding:const EdgeInsets.fromLTRB(12.0, 6.0, 12.0, 12.0),
                      child: Text(
                        dateTimeFormatter.format(txn.dateTime),
                        style: TextStyle(fontSize: 18.0),
                      ),
                    ),
                  ],
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    //crossAxisAlignment: CrossAxisAlignment.end,
                    children: <Widget>[
                      Text(
                        txn.amount.toString(),
                        style: TextStyle(fontSize: 18.0),
                      ),
                    ],
                  ),
                ),
              ],
            ),
            Divider(
              height: 2.0,
              color: Colors.grey,
            )
          ],
        );
      },
    );

    return Scaffold(
       appBar: new AppBar(
         title: new Text('ListView with TextBox'),
       ),
       body: new Column(
         children: <Widget>[
          card,
          Padding(
            padding:const EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 12.0),
            child: Text(
              'Recent transactions',
              style: TextStyle(
                fontSize: 24.0, fontWeight: FontWeight.normal
              ),
              textAlign: TextAlign.center,
            ),
          ),
          //titleSection,
          //buttonSection,
          // new TextField(
          //   controller: textEditingController,
          //   onSubmitted: (text) {
          //     listItems.add(text);
          //     textEditingController.clear();
          //     setState(() {});
          //   },
          // ),
          //textSection,
          // new Expanded(
          //     child: new ListView.builder(
          //       itemCount: listItems.length,
          //       itemBuilder: (BuildContext ctxt, int index) {
          //         return buildBody(context, index);
          //       }
          //     )
          // ),
           new Expanded(
              child: emailView,
           ),
          //gridView,
         ],
       ),
    );
  }
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author

Section 2: ListView with Letter Icons

In this section you will learn how to create a ListView with letter icons, for example like those you see in Contact apps.

Example 1: Flutter ListView with Icons and Text - Contact App

This example will teach you how to create a listview with letter icons. See the demo screenshot below:

Flutter ListView with Icons and Text - Contact App

Step 1: Create Project

Start by creating an empty Flutter project.

Step 2: Dependencies

No special dependency is needed for this project. We also do not need to make any special configuration.

Step 3: Create Model class and Dummy Data

The model class that will hold our Contact data. Then the dummy data to represent our contacts:

contact_data.dart

class Contact {
  final String fullName;
  final String email;

  const Contact({this.fullName, this.email});
}

const List<Contact> kContacts = const <Contact>[
  const Contact(
      fullName: 'Romain Hoogmoed', email: '[email protected]'),
  const Contact(fullName: 'Emilie Olsen', email: '[email protected]'),
  const Contact(fullName: 'Téo Lefevre', email: 'té[email protected]'),
  const Contact(fullName: 'Nicole Cruz', email: '[email protected]'),
  const Contact(fullName: 'Ramna Peixoto', email: '[email protected]'),
  const Contact(fullName: 'Jose Ortiz', email: '[email protected]'),
  const Contact(
      fullName: 'Alma Christensen', email: '[email protected]'),
  const Contact(fullName: 'Sergio Hill', email: '[email protected]'),
  const Contact(fullName: 'Malo Gonzalez', email: '[email protected]'),
  const Contact(fullName: 'Miguel Owens', email: '[email protected]'),
  const Contact(fullName: 'Lilou Dumont', email: '[email protected]'),
  const Contact(
      fullName: 'Ashley Stewart', email: '[email protected]'),
  const Contact(fullName: 'Roman Zhang', email: '[email protected]'),
  const Contact(fullName: 'Ryan Roberts', email: '[email protected]'),
  const Contact(fullName: 'Sadie Thomas', email: '[email protected]'),
  const Contact(fullName: 'Belen Serrano', email: '[email protected] ')
];

Step 4: Create Contact Details Page

Build a screen to render the details of a single Contact in textfields:

/pages/contact_details.dart

import 'package:flutter/material.dart';

import '../models/contact_data.dart';

class ContactViewPage extends StatelessWidget {
  final Contact contact;

  ContactViewPage({Key key, this.contact}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(contact.fullName),
        ),
        body: Container(
          child: Text(contact.email),
        ));
  }
}

Step 5: Create Contacts List Page

This is the screen that will list all the contacts in a listview:

/pages/contact_view.dart

import 'package:flutter/material.dart';

import '../models/contact_data.dart';
import 'contact_details.dart';

class ContactsPage extends StatelessWidget {
  Drawer buildDrawer(BuildContext context) {
    var header = DrawerHeader(
        child: Container(
          child: Text("Contact App Header"),
        ));

    var about = AboutListTile(
      child: Text("About Contact"),
      applicationName: "Contact App Example",
      applicationVersion: "V0.0.1",
      applicationIcon: Icon(Icons.hourglass_empty),
      icon: Icon(Icons.info),
    );

    ListTile buildNavItem(var icon, String label, String route) {
      return ListTile(
        leading: Icon(icon),
        title: Text(label),
        onTap: () {
          // FIXME: Need Stateful Widget
          // setState(() {
          //   Navigator.of(context).pop();
          //   Navigator.of(context).pushNamed(route);
          // });
        },
      );
    }

    var navList = [
      header,
      buildNavItem(Icons.home, "Home", "/"),
      buildNavItem(Icons.settings, "Settings", "/contact_details"),
      buildNavItem(Icons.account_balance_wallet, "Account", "/account"),
      about
    ];

    ListView listView = ListView(children: navList);

    return Drawer(child: listView);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Contacts"),
        ),
        drawer: buildDrawer(context),
        body: Container(
          child: ContactList(kContacts),
        ));
  }
}

class ContactList extends StatelessWidget {
  final List<Contact> _contacts;

  ContactList(this._contacts);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      padding: const EdgeInsets.symmetric(vertical: 8.0),
      itemCount: _contacts.length,
      itemBuilder: _buildContacts,
    );
  }

  Widget _buildContacts(context, index) {
    return ContactItem(_contacts[index]);
  }
}

class ContactItem extends StatelessWidget {
  const ContactItem(this.contact);

  final Contact contact;

  Widget _buildTiles(BuildContext context, Contact contact) {
    return ListTile(
      title: Text(contact.fullName),
      subtitle: Text(contact.email),
      leading: CircleAvatar(
        child: Text(contact.fullName[0]),
      ),
      trailing: Icon(Icons.card_travel),
      onTap: () {
        Navigator.of(context).push(
          MaterialPageRoute(
            builder: (context) {
              // TODO: 어떻게 page간 데이터를 넘기는지?
              return ContactViewPage(contact: contact);
              // return Scaffold(
              //   appBar: AppBar(
              //     title: Text(contact.fullName)
              //   ),
              //   body: Text('Hello'),
              // );
            },
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return _buildTiles(context, contact);
  }
}

Step 6: Create Main class

The main class of this app:

main.dart

import 'package:flutter/material.dart';

import './pages/contact_view.dart';

void main() {
  runApp(new MaterialApp(
    title: 'Flutter Demo',
    theme: new ThemeData(primarySwatch: Colors.blue),
    home: new ContactsPage(),
  ));
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author

Section 3: ListView with Images and Text

In this section we will look at the following:

  1. Create a ListView with CardViews with Images and text

Example 1: Creating a Simple ListView using Columns

This next example is an alternative way to create a ListView. It teaches you how to implement a listview with cardviews that contain images and text. However this time round we create a simple listview using Columns as opposed to the ListItemBuilder.

Check the screenshot below to see how it looks:

ListView with Images and Text

Step 1: Create Project

Start by creating an empty Flutter project in your IDE or editor.

Step 2: Dependencies

No special dependencies are needed for this project. However we will register our assets folder inside the pubspec.yaml

pubspec.yaml

  # To add assets to your application, add an assets section, like this:
  assets:
    - img/

Step 3: Create a Person Object

We now need to create our model class. In this case the Person class is that model class, alongside it's properties like name and profile image:

Person.dart

class Person {
  String name;
  String profileImg;
  String bio;

  Person({this.name,this.profileImg,this.bio});
}

Step 4: Create Main class

Here is how you design a single person's detail card:

   Widget personDetailCard(Person) {
     return Padding(
       padding: const EdgeInsets.all(10.0),
       child: Card(
         color: Colors.grey[800],
         child: Padding(
           padding: const EdgeInsets.all(8.0),
           child: Row(
             children: <Widget>[
               Padding(
                 padding: const EdgeInsets.all(8.0),
                 child: Container(
                     width: 50.0,
                     height: 50.0,
                     decoration: new BoxDecoration(
                         shape: BoxShape.circle,
                         image: new DecorationImage(
                             fit: BoxFit.cover,
                             image: AssetImage(Person.profileImg)
                         )
                     )),
               ),
               Column(
                 crossAxisAlignment: CrossAxisAlignment.start,
                 children: <Widget>[
                   Text(Person.name,
                     style: TextStyle (
                         color: Colors.white,
                         fontSize: 18
                     ),
                   ),
                   Text(Person.bio,
                     style: TextStyle (
                         color: Colors.white,
                         fontSize: 12
                     ),
                   )
                 ],
               )
             ],
           ),
         ),
       ),
     );
   }

Here is the full code:

main.dart

import 'package:flutter/material.dart';
import 'package:custom_list_flutter_app/Person.dart';

void main() => runApp(MaterialApp(
  home: MyHome(),
));

class MyHome extends StatefulWidget {

  @override
  _MyHomeState createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {

   List<Person> persons = [
     Person(name: 'Bill Will', profileImg: 'img/pic-1.png', bio: "Software Developer"),
     Person(name: 'Andy Smith', profileImg: 'img/pic-2.png', bio: "UI Designer"),
     Person(name: 'Creepy Story', profileImg: 'img/pic-3.png', bio: "Software Tester")
  ];

   Widget personDetailCard(Person) {
     return Padding(
       padding: const EdgeInsets.all(10.0),
       child: Card(
         color: Colors.grey[800],
         child: Padding(
           padding: const EdgeInsets.all(8.0),
           child: Row(
             children: <Widget>[
               Padding(
                 padding: const EdgeInsets.all(8.0),
                 child: Container(
                     width: 50.0,
                     height: 50.0,
                     decoration: new BoxDecoration(
                         shape: BoxShape.circle,
                         image: new DecorationImage(
                             fit: BoxFit.cover,
                             image: AssetImage(Person.profileImg)
                         )
                     )),
               ),
               Column(
                 crossAxisAlignment: CrossAxisAlignment.start,
                 children: <Widget>[
                   Text(Person.name,
                     style: TextStyle (
                         color: Colors.white,
                         fontSize: 18
                     ),
                   ),
                   Text(Person.bio,
                     style: TextStyle (
                         color: Colors.white,
                         fontSize: 12
                     ),
                   )
                 ],
               )
             ],
           ),
         ),
       ),
     );
   }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[900],
      body: Padding(
        padding: const EdgeInsets.fromLTRB(10, 50, 10, 10),
        child: Column(
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Icon(Icons.menu, size: 35, color: Colors.white),
                Text('Notifications',
                  style: TextStyle (
                    color: Colors.white,
                    fontSize: 25
                  ),
                ),
                Icon(Icons.notifications_none, size: 35, color: Colors.white)
              ],
            ),
            Column(
              children: persons.map((p) {
                return personDetailCard(p);
              }).toList()
            )
          ],
        ),
      ),
    );
  }
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author

Example 2: Swipe-Dismiss ListView with CardView, Images and Multiple Text

This example will contain cardview with images and multiple text for each row on our Card. We use ListView.Builder. The rows or rather the cards can be swiped and dismissed subsequently.

Here is the demo of the project:

Here are what you will learn:

  1. How to implement listview with images and multiple text.
  2. How to implement swipe to dismiss in a listview.
  3. How to load ListView images from the network using NetworkImage.

Step 1: Create Project

Start by creating an empty Android Studio project.

Step 2: Dependencies

No special dependency or configuration is needed for this project.

Step 3: Create Swipeable ListView

Replace your main.dart with the following code:

main.dart

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("List view"),
        ),
        body: Center(child: SwipeList()));
  }
}

class SwipeList extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return ListItemWidget();
  }
}

class ListItemWidget extends State<SwipeList> {
  List items = getDummyList();

  @override
  Widget build(BuildContext context) {
    return Container(
        child: ListView.builder(

      itemCount: items.length,
      itemBuilder: (context, index) {
        return Dismissible(
          key: Key(items[index]),
          background: Container(
            alignment: AlignmentDirectional.centerEnd,
            color: Colors.red,
            child: Icon(
              Icons.delete,
              color: Colors.white,
            ),
          ),
          onDismissed: (direction) {
            setState(() {
              items.removeAt(index);
            });
          },
          direction: DismissDirection.endToStart,
          child: Card(
              elevation: 5,
              child: Container(
              height: 100.0,
              child: Row(
                children: <Widget>[
                  Container(
                    height: 100.0,
                    width: 70.0,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.only(
                        bottomLeft: Radius.circular(5),
                        topLeft: Radius.circular(5)
                      ),
                      image: DecorationImage(
                        fit: BoxFit.cover,
                        image: NetworkImage("https://is2-ssl.mzstatic.com/image/thumb/Video2/v4/e1/69/8b/e1698bc0-c23d-2424-40b7-527864c94a8e/pr_source.lsr/268x0w.png")
                      )
                    ),
                  ),
                  Container(
                    height: 100,
                    child: Padding(
                      padding: EdgeInsets.fromLTRB(10, 2, 0, 0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          Text(
                            items[index],

                          ),
                          Padding(
                              padding: EdgeInsets.fromLTRB(0, 3, 0, 3),
                               child: Container(
                              width: 30,
                              decoration: BoxDecoration(
                                border: Border.all(color: Colors.teal),
                                borderRadius: BorderRadius.all(Radius.circular(10))
                              ),
                              child: Text("3D",textAlign: TextAlign.center,),
                            ),
                          ),
                          Padding(
                            padding: EdgeInsets.fromLTRB(0, 5, 0, 2),
                              child: Container(
                              width: 260,
                              child: Text("His genius finally recognized by his idol Chester",style: TextStyle(
                                fontSize: 15,
                                color: Color.fromARGB(255, 48, 48, 54)
                              ),),

                            ),
                          )
                        ],
                      ),
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      },
    ));
  }

  static List getDummyList() {
    List list = List.generate(10, (i) {
      return "Item ${i + 1}";
    });
    return list;
  }
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author

Example 3: ListView with Images and Chips - onTap with GestureDetector

This example teaches you how to create a simple listview containing cardview with images and Chips. We handle click events using GestureDetector.

Check the demo screenshot below:

ListView with CardView, Images and Text

Here are what you will learn:

  1. Create a listview with images and text.
  2. Use GestureDetector - When the user taps an item in our list, we will capture the event using GestureDetector and thus show a dialog
  3. Create a Listview with Chips - Our text will be rendered on a chip.

Step 1: Create Project

Start by creating an empty flutter project.

Step 2: Dependencies

In you pubspec.yaml add photo_view as a dependency:

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  photo_view: ^0.5.0

Also register the images folder as a asset:

  # To add assets to your application, add an assets section, like this:
  assets:
    - images/hacker.jpeg

Step 3: Create ListView

We create our ListView using the ListView.Builder:

main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        appBarTheme: AppBarTheme(color: Colors.green),
        primarySwatch: Colors.purple,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(
        title: Text('Simple Card view'),
      ),
      body: new ListView.builder(
        padding: const EdgeInsets.all(16),
        itemBuilder: (context, i) {
          return Container(
            height: 130,
            child: Card(
//                color: Colors.blue,
              elevation: 10,
              child: Row(
                children: <Widget>[
                  Padding(
                    padding: EdgeInsets.all(10.0),
                    child: GestureDetector(
                      onTap: () {

                      },
                      child: Container(
                        width: 100.0,
                        height: 100.0,
                        decoration: BoxDecoration(
                            color: Colors.red,
                            image: DecorationImage(
                                image: AssetImage('images/hacker.jpeg'),
                                fit: BoxFit.cover),
                            borderRadius:
                                BorderRadius.all(Radius.circular(75.0)),
                            boxShadow: [
                              BoxShadow(blurRadius: 7.0, color: Colors.black)
                            ]),
                      ),
                    ),
                  ),
                  GestureDetector(
                    onTap: () {
                      return showDialog<void>(
                        context: context,
                          barrierDismissible: false,
                          builder: (BuildContext conext) {
                          return AlertDialog(
                            title: Text('Not in stock'),
                            content:
                                const Text('This item is no longer available'),
                            actions: <Widget>[
                              FlatButton(
                                child: Text('Ok'),
                                onPressed: () {
                                  Navigator.of(context).pop();
                                },
                              ),
                            ],
                          );
                        },
                      );
                    },
                    child: Container(
                        padding: EdgeInsets.all(30.0),
                        child: Chip(
                          label: Text('@anonymous'),
                          shadowColor: Colors.blue,
                          backgroundColor: Colors.green,
                          elevation: 10,
                          autofocus: true,
                        )),
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author

Section 4: ListView Scroll Examples

In this section we will look at examples regarding scrolling of a listview, be it vertical or horizontal.

Example 1: ListView Scroll Horizontally or Vertically

This example explores how to create a ListView that can scroll in both directions: horizontally or vertically, sideways or up and down.

Here is the demo:

ListView Scroll Horizontally or Vertically

Step 1: Create Project

Start by creating an empty Flutter project.

Step 2: Dependencies

No special or third party dependency is needed. We also do not need any special configuration.

Step 3: Create Horizontal and Vertical ListView

The screen will contain a BottomNavigationBar with three BottomNavigationBarItems. Each item represents a different Listview. Tehre are three listview types in this case: the Normal ListView, the Vertical ListView and the Horizontal ListView.

Here is how you build a widget or screen with a bottom navigation bar:

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: buildListViews(),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: index,
          items: [
            BottomNavigationBarItem(
              icon: Text('ListView'),
              title: Text('Basic'),
            ),
            BottomNavigationBarItem(
              icon: Text('ListView'),
              title: Text('Vertical'),
            ),
            BottomNavigationBarItem(
              icon: Text('ListView'),
              title: Text('Horizontal'),
            ),
          ],
          onTap: (int index) => setState(() => this.index = index),
        ),
      );

Here is how you build a verical List:`

  Widget buildVerticalListView() => ListView.separated(
        separatorBuilder: (context, index) => Divider(color: Colors.black),
        itemCount: items.length,
        itemBuilder: (context, index) {
          final item = items[index];

          return ListTile(
            title: Text(item),
          );
        },
      );

And here is how you build a horizontal listview:

  Widget buildHorizontalListView() => Container(
        height: 100,
        child: ListView.separated(
          padding: EdgeInsets.all(16),
          scrollDirection: Axis.horizontal,
          separatorBuilder: (context, index) => Divider(),
          itemCount: items.length,
          itemBuilder: (context, index) {
            final item = items[index];

            return Container(
              alignment: Alignment.center,
              margin: EdgeInsets.only(right: 16),
              child: Text(item, style: TextStyle(fontSize: 24)),
            );
          },
        ),
      );

Here is the full code:

main.dart

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  static final String title = 'ListView Example';

  @override
  Widget build(BuildContext context) => MaterialApp(
        debugShowCheckedModeBanner: false,
        title: title,
        theme: ThemeData(primarySwatch: Colors.deepOrange),
        home: MainPage(title: title),
      );
}

class MainPage extends StatefulWidget {
  final String title;

  const MainPage({
    @required this.title,
  });

  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int index = 0;
  final items = List.generate(2000, (counter) => 'Item: $counter');

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: buildListViews(),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: index,
          items: [
            BottomNavigationBarItem(
              icon: Text('ListView'),
              title: Text('Basic'),
            ),
            BottomNavigationBarItem(
              icon: Text('ListView'),
              title: Text('Vertical'),
            ),
            BottomNavigationBarItem(
              icon: Text('ListView'),
              title: Text('Horizontal'),
            ),
          ],
          onTap: (int index) => setState(() => this.index = index),
        ),
      );

  Widget buildListViews() {
    if (index == 0) {
      return buildBasicListView();
    } else if (index == 1) {
      return buildVerticalListView();
    } else if (index == 2) {
      return buildHorizontalListView();
    } else {
      return Container();
    }
  }

  Widget buildBasicListView() => ListView(
        children: [
          ListTile(
            leading: Icon(Icons.arrow_forward_ios),
            title: Text('Favourites'),
            subtitle: Text('All your favourite widgets'),
            trailing: Icon(Icons.star, color: Colors.orange),
          ),
          ListTile(
            leading: Icon(Icons.arrow_forward_ios),
            title: Text('High Ranked'),
            subtitle: Text('All widgets liked by the community'),
            trailing: Icon(Icons.mood, color: Colors.blue),
          ),
          ListTile(
            leading: Icon(Icons.arrow_forward_ios),
            title: Text('Important'),
            subtitle: Text('All widgets that are important to know'),
            trailing: Icon(Icons.assistant_photo, color: Colors.black),
          ),
          ListTile(
            leading: Icon(Icons.delete_forever, color: Colors.red),
            title: Text('Deleted'),
            onTap: () {
              print('Deleted pressed');
            },
          ),
        ],
      );

  Widget buildVerticalListView() => ListView.separated(
        separatorBuilder: (context, index) => Divider(color: Colors.black),
        itemCount: items.length,
        itemBuilder: (context, index) {
          final item = items[index];

          return ListTile(
            title: Text(item),
          );
        },
      );

  Widget buildHorizontalListView() => Container(
        height: 100,
        child: ListView.separated(
          padding: EdgeInsets.all(16),
          scrollDirection: Axis.horizontal,
          separatorBuilder: (context, index) => Divider(),
          itemCount: items.length,
          itemBuilder: (context, index) {
            final item = items[index];

            return Container(
              alignment: Alignment.center,
              margin: EdgeInsets.only(right: 16),
              child: Text(item, style: TextStyle(fontSize: 24)),
            );
          },
        ),
      );
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author

Section 5: How to Sort Data in ListViews

In this section we will look at flutter examples for sorting ListViews, or how to create sortable Lists easily.

Example 1: How to Create a Sortable ListView

This example teaches you how to create a sortable listview in flutter.

Step 1: Create Project

Start by creating an empty flutter project.

Step 2: Dependencies

We do not need any special dependency to create our sortable listview.

Step 3: Create Sortable Listview

The items and the ListView builder are passed via the constructor.
We will create our Listview as a StatefulWidget:

class SortableListView extends StatefulWidget {
  final List items;
  final IndexedWidgetBuilder itemBuilder;

  SortableListView({this.items, this.itemBuilder})
      : assert(items != null),
        assert(itemBuilder != null);

  @override
  State createState() => new SortableListViewState();
}

Here is the full code:

main.dart

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatefulWidget {
  @override
  MyAppState createState() => new MyAppState();
}

class MyAppState extends State<MyApp> {
  List<String> rows = new List<String>()
    ..add('Row 1')
    ..add('Row 2')
    ..add('Row 3')
    ..add('Row 4');

  @override
  Widget build(BuildContext context) {
    final title = 'Sortable ListView';

    return new MaterialApp(
      title: title,
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text(title),
        ),
        body: new SortableListView(
          items: rows,
          itemBuilder: (_, int index) => new Card(
                child: new ListTile(
                    leading: new Icon(Icons.photo),
                    title: new Text(rows[index])),
              ),
        ),
      ),
    );
  }
}

class SortableListView extends StatefulWidget {
  final List items;
  final IndexedWidgetBuilder itemBuilder;

  SortableListView({this.items, this.itemBuilder})
      : assert(items != null),
        assert(itemBuilder != null);

  @override
  State createState() => new SortableListViewState();
}

class SortableListViewState extends State<SortableListView> {
  @override
  Widget build(BuildContext context) {
    return new LayoutBuilder(
      builder: (context, constraint) {
        return new ListView.builder(
          itemCount: widget.items.length + 1,
          addRepaintBoundaries: true,
          itemBuilder: (context, index) {
            return new LongPressDraggable<int>(
              data: index,
              child: new DragTarget<int>(
                onAccept: (int data) {
                  _handleAccept(data, index);
                },
                builder: (BuildContext context, List<int> data,
                    List<dynamic> rejects) {
                  List<Widget> children = [];

                  // If the dragged item is on top of this item, the we draw
                  // a half-visible item to indicate that dropping the dragged
                  // item will add it in this position.
                  if (data.isNotEmpty) {
                    children.add(
                      new Container(
                        decoration: new BoxDecoration(
                          border: new Border.all(
                              color: Colors.grey[600], width: 2.0),
                        ),
                        child: new Opacity(
                          opacity: 0.5,
                          child: _getListItem(context, data[0]),
                        ),
                      ),
                    );
                  }
                  children.add(_getListItem(context, index));

                  return new Column(
                    children: children,
                  );
                },
              ),
              onDragStarted: () {
                Scaffold.of(context).showSnackBar(
                      new SnackBar(
                          content: new Text("Drag the row to change places")),
                    );
              },
              feedback: new Opacity(
                opacity: 0.75,
                child: new SizedBox(
                  width: constraint.maxWidth,
                  child: _getListItem(context, index, true),
                ),
              ),
              childWhenDragging: new Container(),
            );
          },
        );
      },
    );
  }

  void _handleAccept(int data, int index) {
    setState(() {
      // Decrement index so that after removing we'll still insert the item
      // in the correct position.
      if (index > data) {
        index--;
      }
      dynamic imageToMove = widget.items[data];
      widget.items.removeAt(data);
      widget.items.insert(index, imageToMove);
    });
  }

  Widget _getListItem(BuildContext context, int index, [bool dragged = false]) {
    // A little hack: our ListView has an extra invisible trailing item to
    // allow moving the dragged item to the last position.
    if (index == widget.items.length) {
      // This invisible item uses the previous item to determine its size. If
      // the list is empty, though, there's no dragging really.
      if (widget.items.isEmpty) {
        return new Container();
      }
      return new Opacity(
        opacity: 0.0,
        child: _getListItem(context, index - 1),
      );
    }

    return new Material(
      elevation: dragged ? 20.0 : 0.0,
      child: widget.itemBuilder(context, index),
    );
  }
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author