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 ❤️