A list is a key UI element for mobile apps. You’ll learn all about how to create lists in your Flutter app in this tutorial.
You don’t need to be an expert developer to create lists in your Flutter app. If you’ve developed apps for Android or iOS in the past, Flutter’s ListView
should seem like a piece of cake to you. And if you’re just getting started with Flutter development, just follow along and you’ll see how easy it can be.
In this tutorial, I’ll show you examples of a few common Flutter ListView
patterns. You can easily reuse these for your own amazing app.
Flutter ListView
Examples
Now, let’s start a project using Android Studio with Flutter 1.0 and call it Flutter_view
.
So, keep in mind that this code here works as a head for all the code snippets of ListsViews
mentioned after this.
import 'package:Flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'ListViews', theme: ThemeData( primarySwatch: Colors.teal, ), home: Scaffold( appBar: AppBar(title: Text('ListViews')), body: BodyLayout(), ), ); } } class BodyLayout extends StatelessWidget { @override Widget build(BuildContext context) { return _myListView(context); } }
Essentially, there a few types of ListView
that can be used for a Flutter project. The choice of lists is dependent upon the aesthetic vision and the user interface of the app. Developers are often asked to finding a balance between creativity and practicality for the menu bars and option lists in the app.
Let’s look at the different kinds of lists you can have in your Flutter app.
Static Lists
When you have limited options, then you can use static lists found in the default Flutter ListView
builder. Static lists are ideal for creating a menu page.
Here is a snippet of code that you can use:
Widget _myListView(BuildContext context) { return ListView( children: <Widget>[ ListTile( title: Text('Black'), ), ListTile( title: Text('White'), ), ListTile( title: Text('Grey'), ), ], ); }
And here’s what it will look like:
This list of colors only includes titles. But you can customize the ListTile
with subtitles, images, and even icons.
Dynamic Lists
When you create a static list, all the elements are created at once. Short lists benefit from this technique. However, when you offer a long list of options like for choosing the country for an international shipment, then you need the ListView.builder()
constructor for a dynamic list.
Replace myListView()
with this snippet:
Widget _myListView(BuildContext context) { // backing data final europeanCountries = ['Albania', 'Andorra', 'Armenia', 'Austria', 'Azerbaijan', 'Belarus', 'Belgium', 'Bosnia and Herzegovina', 'Bulgaria', 'Croatia', 'Cyprus’]; return ListView.builder( itemCount: europeanCountries.length, itemBuilder: (context, index) { return ListTile( title: Text(europeanCountries[index]), ); }, ); }
Your app will now offer a list like this:
When you enter an itemCount
in the code, then the ListView
builder on Flutter prepares a specific number of options at a time. The itemBuilder
can also be used to view each ListTile
individually. The use of an index
makes it easier to extract data from the list of European country names that have been used as the backing information here.
Infinite Lists
Many applications require infinite lists—this had always been challenging for Android and iOS in the past. However with Flutter, you can simply alter the itemCount
parameter and change the ListTile
to display the row index like this:
Here’s the snippet of code:
Widget _myListView(BuildContext context) { return ListView.builder( itemBuilder: (context, index) { return ListTile( title: Text('row $index'), ); }, ); }
This code just dynamically generates each ListTile
when it is needed, so the list view can have as many rows as you need. The ListView
will intelligently decide when to generate each tile so that it is available when that part of the list is visible.
If you want to take this a step further then you can add dividers in the dynamic list to give your app a more organized look. Here’s how you can do it:
Widget _myListView(BuildContext context) { return ListView.separated( itemCount: 1000, itemBuilder: (context, index) { return ListTile( title: Text('row $index'), ); }, separatorBuilder: (context, index) { return Divider(); }, ); }
And here’s how the list looks with dividers:
The height and color of these dividers can be changed with arguments to the Divider()
constructor.
Horizontal Lists
While all the previous lists have been on the y axis, you can easily create a list horizontally on Flutter! A simple specification of the scrollDirection
can be used on a custom layout to accommodate a horizontal list.
This is how you can do it:
Widget _myListView(BuildContext context) { return ListView.builder( scrollDirection: Axis.horizontal, itemBuilder: (context, index) { return Container( margin: const EdgeInsets.symmetric(horizontal: 1.0), color: Colors.black26, child: Text('$index'), ); }, ); }
And here’s what the list looks like in the horizontal axis:
Custom ListTile
s
Now that we have covered the most common types of ListViews
, it is time to spruce up the aesthetics of the application. Flutter ensures that your mobile app looks easy on the eyes and offers a wide variety of widgets to accommodate the needs of the developer.
The ListTile
widget is used to handle the normal content displayed in lists. This works well when there are no customizations involved in the layout.
When we made the first list of colors, only the ListView
was used. But now, we can introduce details such as images, subtitles, and even icons.
Follow along:
Widget _myListView(BuildContext context) { return ListView( children: <Widget>[ ListTile( leading: Icon(Icons.wb_sunny), title: Text('Sun'), ), ListTile( leading: Icon(Icons.brightness_3), title: Text('Moon'), ), ListTile( leading: Icon(Icons.star), title: Text('Star'), ), ], ); }
This code would achieve this look:
While the touch-ability of the list can be toggled with onTap
, we will take the customization of the list a little further. If you want to add images instead of icons to personalize the app, then the recommended widget is the CircleAvatar
.
Widget _myListView(BuildContext context) { return ListView( children: <Widget>[ ListTile( leading: CircleAvatar( backgroundImage: AssetImage('assets/sun.jpg'), ), title: Text('Sun'), ), ListTile( leading: CircleAvatar( backgroundImage: AssetImage('assets/moon.jpg'), ), title: Text('Moon'), ), ListTile( leading: CircleAvatar( backgroundImage: AssetImage('assets/stars.jpg'), ), title: Text('Star'), ), ], ); }
You could use the NetworkImage(imageUrl)
and ditch the AssetImage(path)
but remember, when you need the images to remain self-contained, the latter is a better option.
Register the location of the assets in pubspec.yaml
:
Flutter: assets: - assets/
Restart the app and you are all good to go!
Flutter Lists and Data Sources
Let’s finish with something interesting: did you know Flutter allows you to create a data source with various types of items and it also facilitates the conversion of the data source into a large list of widgets?
So, you can use a Flutter list to display a heading with a list of options or expand upon the specifications of product details, heading by heading?
First let’s take a look at the completed list:
And here’s the code that generated that list:
import 'package:flutter/material.dart'; void main() { runApp(MyApp( items: List<ListItem>.generate( 1000, (i) => i % 6 == 0 ? HeadingItem("Heading $i") : MessageItem("Sender $i", "Message body $i"), ), )); } class MyApp extends StatelessWidget { final List<ListItem> items; MyApp({Key key, @required this.items}) : super(key: key); @override Widget build(BuildContext context) { final title = 'Mixed List'; return MaterialApp( title: title, home: Scaffold( appBar: AppBar( title: Text(title), ), body: ListView.builder( // Let the ListView know how many items it needs to build. itemCount: items.length, // Provide a builder function. This is where the magic happens. // Convert each item into a widget based on the type of item it is. itemBuilder: (context, index) { final item = items[index]; return ListTile( title: item.buildTitle(context), subtitle: item.buildSubtitle(context), ); }, ), ), ); } } /// The base class for the different types of items the list can contain. abstract class ListItem { /// The title line to show in a list item. Widget buildTitle(BuildContext context); /// The subtitle line, if any, to show in a list item. Widget buildSubtitle(BuildContext context); } /// A ListItem that contains data to display a heading. class HeadingItem implements ListItem { final String heading; HeadingItem(this.heading); Widget buildTitle(BuildContext context) { return Text( heading, style: Theme.of(context).textTheme.headline5, ); } Widget buildSubtitle(BuildContext context) => null; } /// A ListItem that contains data to display a message. class MessageItem implements ListItem { final String sender; final String body; MessageItem(this.sender, this.body); Widget buildTitle(BuildContext context) => Text(sender); Widget buildSubtitle(BuildContext context) => Text(body); }
The code for this example is a bit more complicated than the others and I won’t explain it in detail. But feel free to play around with the code and see if you can get it to work the way you want for your app! This element offers you a great way to keep a humongous amount of content on your app organized.
Final Thoughts
With ListView
s you can add subtitles and cards to enhance the aesthetics and even opt for farfetched maximalist ideas for your app as well. However, I would suggest you keep your design minimal as that is the design trend for the year.
But the choice is all yours!
I hope this has helped you understand the basics of lists and a little customization along the way. In the end, it all depends how creative you want to get, because the possibilities Flutter offers are limitless.