Displaying elements in a list is a very common pattern in mobile applications. The user sees a collection of items and can scroll through them. The collection of items can be a list, a grid or another structured representation of data.
In this tutorial, we are going to learn how to create a simple ListView from a list of items. We’ll also learn to add items, add divider and onTap on the item. The ListView we are going to design contains a list of String.
1. Create Datasource
First, we’ll need a data source to work with ListView. For example, your data source might be a list of items, or products in a store. Most of the time, this data will come from the internet or a database.
class Item {
Item({this.name, this.isSelected});
String name;
bool isSelected;
}
for (var i = 0; i < 15; i++) {
items.add(new Item(name: "Default Items", isSelected: false));
2.Create Stateful Widget
Stateful widgets are useful when the list of items can change dynamically, e.g. add or remove items from list.
class ListScreen extends StatefulWidget {
@override
_ListScreenState createState() => _ListScreenState();
}
class _ListScreenState extends State<ListScreen> {
List<Item> items = new List();
_addItems() {
setState(() {
items.add(new Item(name: "My Item name", isSelected: false));
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
for (var i = 0; i < 15; i++) {
items.add(new Item(name: "Default Items", isSelected: false));
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Dynamic List"),
),
body: new StringList(items: items),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: _addItems,
),
);
}
}
First, we have created a stateful widget. Then we have taken one
3.Create ListView Widget
In order to display our List of Items, we’ll need to render each item as a Widget.
class StringList extends StatelessWidget {
final List<Item> items;
StringList({@required this.items});
Widget build(BuildContext context) {
// TODO: implement build
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index].name}'),
);
},
);
}
}
ListView.builder creates a scrollable, linear array of widgets that are created on demand.
4.Adding ListView Divider
ListView.separated constructor is appropriate for list views with a large number of item and separator children. Separators only appear between list items: separator 0 appears after item 0 and the last separator appears before the last item.
return ListView.separated(
itemCount: items.length,
separatorBuilder: (BuildContext context, int index) => Divider(
color: Colors.deepOrange,
),
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index].name}'),
);
},
);
5.Handling onTap Events
onTap event Called when the user taps this list tile.
return ListTile(
title: Text('${items[index].name}'),
onTap: () {
print("Item at $index is ${items[index].name}");
},
);
Complete example
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class Item {
Item({this.name, this.isSelected});
String name;
bool isSelected;
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Dynamic List',
home: ListScreen(),
);
}
}
class ListScreen extends StatefulWidget {
@override
_ListScreenState createState() => _ListScreenState();
}
class _ListScreenState extends State<ListScreen> {
List<Item> items = new List();
_addItems() {
setState(() {
items.add(new Item(name: "My Item name", isSelected: false));
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
for (var i = 0; i < 15; i++) {
items.add(new Item(name: "Default Items", isSelected: false));
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Dynamic List"),
),
body: new StringList(items: items),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: _addItems,
),
);
}
}
class StringList extends StatelessWidget {
final List<Item> items;
StringList({@required this.items});
Widget build(BuildContext context) {
// TODO: implement build
return ListView.separated(
itemCount: items.length,
separatorBuilder: (BuildContext context, int index) => Divider(
color: Colors.deepOrange,
),
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index].name}'),
);
},
);
}
}