Introducing FlatList in Flutter

Hyo
dooboolab
Published in
5 min readNov 12, 2022

I like to share the [FlatList] widget in Flutter which will be familiar to React Native developers.

Today, I’ve been working on a project written in Flutter and my lastest project was in React Native. Although I already have experience in both frameworks, I still face a few pros and cons while working on Flutter.

I want to go further on a detailed comparison between the two frameworks in a later post but today, I’d like to share my work on [FlatList] widget with Flutter.

Motivation

The motivation to develop FlatList stems from an effort to reduce the time required to create a variety of common listviews and simplify the code.

While there are opinionated ways to build a ListView in React Native, there are many ways to build ListView in Flutter. In Flutter, we can use ListView, ListView.builder(), SliverList, and also when you want to make list with more than one column, you need to use GridView, SliverGrid and so on.

Another discomfort while building listviews in Flutter is that each of those widgets lacks features so you will be asking lots of questions on Stackoverflow when you try to achieve what you want to build.

Here are some sample asked questions while building listviews in Flutter.

- How to add a header row to a listview?
- How to add listview with a scrolling footer at the bottom?
- How to refresh listview builder?
- How can you add header to GridView?
- How can I display an image or text when my List is empty?
- How to add infinite scrolling for ListView.builder?

When looking back on when I was using React Native, I’ve not had any problem implementing them with just a FlatList. I wanted to unify these various individual problems by providing a FlatList widget.

Flutter’s FlatList

I’ll show you what you can do with the early flat_list widget.

Installation

flutter pub add flat_list

1. The simple version.

FlatList(
data: items.value,
buildItem: (item, index) {
var person = items.value[index];

return ListItemView(person: person);
},
)

The sample widget is built with flutter_hooks. The items.value is a hook state variable. The data and buildItem are only required props to use the FlatList. The buildItem method is identical to renderItem in React Native.

2. The header that is scrollable with other list items.

FlatList(
+ listHeaderWidget: const Header(),
data: items.value,
buildItem: (item, index) {
var person = items.value[index];

return ListItemView(person: person);
},
),

By adding listHeaderWidget, you can add a view on top of your list of item views. This is similar to ListHeaderComponent in React Native.

3. The footer

FlatList(
listHeaderWidget: const Header(),
+ listFooterWidget: const Footer(),
data: items.value,
buildItem: (item, index) {
var person = items.value[index];

return ListItemView(person: person);
},
),

By adding listFooterWidget, you can add a view at the bottom of your list of item views. This is similar to ListFooterComponent in React Native.

4. Empty view when data is empty

FlatList(
+ listEmptyWidget: Container(
+ alignment: Alignment.center,
+ padding: const EdgeInsets.all(50),
+ child: const Text('List is empty!'),
+ ),
data: const [],
buildItem: (item, index) {
var person = items.value[index];

return ListItemView(person: person);
},
),
)

By adding listEmptyWidget, you can add custom widget to render when the list is empty.

5. Refreshing view

FlatList(
+ onRefresh: () async {
+ await Future.delayed(const Duration(seconds: 2));

+ if (context.mounted) {
+ items.value = data;
+ }
+ },
listHeaderWidget: const Header(),
listFooterWidget: const Footer(),
listEmptyWidget: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(12),
child: const Text('List is empty!'),
),
data: items.value,
buildItem: (item, index) {
var person = items.value[index];

return ListItemView(person: person);
},
)

Unlike FlatList in React Native, flat_list does not have refreshing props for pull-to-refresh functionality. Therefore, it is easier to use and the refresh indicator will disappear when the futures in onRefresh function is completed.

6. Infinite scroll


FlatList(
+ loading: loading.value,
+ onEndReached: () async {
+ loading.value = true;
+ await Future.delayed(const Duration(seconds: 2));
+ if (context.mounted) {
+ items.value += getMoreData();
+ loading.value = false;
+ }
+ },
onRefresh: () async {
await Future.delayed(const Duration(seconds: 2));

if (context.mounted) {
items.value = data;
}
},
listHeaderWidget: const Header(),
listFooterWidget: const Footer(),
listEmptyWidget: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(12),
child: const Text('List is empty!'),
),
data: items.value,
buildItem: (item, index) {
var person = items.value[index];

return ListItemView(person: person);
},
)

The onEndReaced function is provided which is similar to https://reactnative.dev/docs/flatlist#onendreached. This will help you build the infinite listview. By using extra listLoadingWidget supported in flat_list, you can customize the loading indicator showing at the bottom.

7. Lastly, use numColumns for GridView

FlatList(
numColumns: 2,
loading: loading.value,
onEndReached: () async {
loading.value = true;
await Future.delayed(const Duration(seconds: 2));
if (context.mounted) {
items.value += getMoreData();
loading.value = false;
}
},
onRefresh: () async {
await Future.delayed(const Duration(seconds: 2));

if (context.mounted) {
items.value = data;
}
},
listHeaderWidget: const Header(),
listFooterWidget: const Footer(),
listEmptyWidget: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(12),
child: const Text('List is empty!'),
),
data: items.value,
buildItem: (item, index) {
var person = items.value[index];

return ListItemView(person: person);
},
)

You can easily switch ListView to GridView in Flutter just by changing numColumnns props.

Sample code

Now try it by yourself by installing flat_list. The source code is MIT license and is available at https://github.com/hyochan/flat_list.

The FlatList specification in React Native is ❤️

--

--