Exploring Flutter ListView – Part 1

The ListView class will end up being in most Flutter apps that will display a list of data. So it is a good idea to get up to speed with how they are used. This will be the first post in my series of exploring ListViews.

In this post we will focus on one of the most simplest of use cases - displaying a list of static data in a ListView. Your static data can come from pretty much any source but in our case we will have it hard-coded into the application. A better choice is to deploy a data file (perhaps in JSON format) or to pull down the data from an API. I will cover both of these options in future articles but we're keeping it simple this time around...

Building the App

For our new Flutter app we are going to start off by modifying the build method. Create a new Flutter app and modify the build method so that we can call a body() method:

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: body(context)
    );
  }

The body() method will be used to create our actual ListView. Here is the code for the body method which creates a ListView:

  Widget body(BuildContext context) {
    return ListView(
      children: ListTile.divideTiles(
        context: context,
        tiles: [

        ],
      ).toList(),
    );
  }

A few important points about the code above.

  • Firstly we use ListTile.divideTiles so that we can easily insert a 1 pixel line between the list tiles in our list.
  • Since divideTiles returns an Iterable, we need to call toList() to make sure it is treated as a List
  • We have not given the divideTiles any tiles to divide just yet - we'll do that now.

For the data we will display in our list, I have chosen the Star Wars films. We'll load up the poster images, the title, and the infamous scrolling intro text. Since the intro text is rather long, rather than just use a plain ListTile, we will use and ExpansionTile. The main difference between the two is that the latter allows for children to be displayed when the tile is clicked.

Our end result will look like this:

demo

Constructing the ExpansionTile is rather easy. Our code that displays the Star Wars films looks like this:

tiles: [
  ExpansionTile(
      leading: Image.network(newHopeImage),
      title: Text('A New Hope'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(newHopeText))
      ]),
  ExpansionTile(
      leading: Image.network(empireStrikesBackImage),
      title: Text('The Empire Strikes Back'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(empireStrikesBackText))
      ]),
  ExpansionTile(
      leading: Image.network(returnOfTheJediImage),
      title: Text('Return of the Jedi'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(returnOfTheJediText))
      ]),
  ExpansionTile(
      leading: Image.network(thePhantomMenaceImage),
      title: Text('The Phantom Menace'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(thePhantomMenaceText))
      ]),
  ExpansionTile(
      leading: Image.network(attackOfTheClonesImage),
      title: Text('Attack of the Clones'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(attackOfTheClonesText))
      ]),
  ExpansionTile(
      leading: Image.network(revengeOfTheSithImage),
      title: Text('Revenge of the Sith'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(revengeOfTheSithText))
      ]),
  ExpansionTile(
      leading: Image.network(theForceAwakensImage),
      title: Text('The Force Awakens'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(theForceAwakensText))
      ]),
  ExpansionTile(
      leading: Image.network(theLastJediImage),
      title: Text('The Last Jedi'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(theLastJediText))
      ]),
  ExpansionTile(
      leading: Image.network(theRiseOfSkywalkerImage),
      title: Text('The Rise of Skywalker'),
      children: [
        Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(theRiseOfSkywalkerText))
      ]),
]

But that is a lot of repetitive typing. We can improve this by breaking out the creation of the tiles to a helper method:

  ExpansionTile starWarsTile(String imgUrl, String title, String description) {
    return ExpansionTile(
        leading: Image.network(imgUrl),
        title: Text(title),
        children: [
          Padding(padding: const EdgeInsets.all(8.0), child: Text(description))
        ]);
  }

With our helper method in hand, we can return to the code where we populate our tiles and replace it with calls to the new starWarsTile helper method. For example:

tiles: [
  starWarsTile(newHopeImage, 'A New Hope', newHopeText),
  starWarsTile(empireStrikesBackImage, 'The Empire Strikes Back',
      empireStrikesBackText),
  starWarsTile(
      returnOfTheJediImage, 'Return of the Jedi', returnOfTheJediText),
  starWarsTile(thePhantomMenaceImage, 'The Phantom Menace',
      thePhantomMenaceText),
  starWarsTile(attackOfTheClonesImage, 'Attack of the Clones',
      attackOfTheClonesText),
  starWarsTile(revengeOfTheSithImage, 'Revenge of the Sith',
      revengeOfTheSithText),
  starWarsTile(
      theForceAwakensImage, 'The Force Awakens', theForceAwakensText),
  starWarsTile(theLastJediImage, 'The Last Jedi', theLastJediText),
  starWarsTile(theRiseOfSkywalkerImage, 'The Rise of Skywalker',
      theRiseOfSkywalkerText),
]

Now, if you run the app, you will see the exact same results but the code is a lot easier to maintain and understand.

Special thanks to https://swapi.co/ and http://www.omdbapi.com/ for making the Star Wars related information available on the web.

Summary

Displaying a list of items in Flutter is pretty straight-forward but there are lots of different ways to achieve the desired result. This article explored one of the simplest yet effective ways of displaying a list of items where tapping on an item would display additional information. That information could be in any number of widgets and just because I chose a Text widget for a child widget doesn't mean that is your only choice. Keep your eyes out for more articles related to Flutter ListView.

Leave a Reply

Your email address will not be published. Required fields are marked *