Now that you have gone through a handful of Widgets that will help you create really amazing Ui’s in Flutter, its time to expand your knowledge to some more important widgets and concepts. In this tutorial you will learn how to create a list in Flutter and how to open up a new page, while passing data to it.

ListView in Flutter

Flutter provides a ListView widget which helps making lists as easy as it can get. It’s a straight forward widget, so lets directly look at the code.

Flutter ListView class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView'), ), body: ListView.builder( itemCount: 100, itemBuilder: (context, index) { return Container( padding: EdgeInsets.all(16.0), child: Text('Item #$index'), ); }, ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Home extends StatelessWidget { @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'ListView' ) , ) , body : ListView . builder ( itemCount : 100 , itemBuilder : ( context , index ) { return Container ( padding : EdgeInsets . all ( 16.0 ) , child : Text ( 'Item #$index' ) , ) ; } , ) , ) ; } }

We have used the ListView.builder constructor to build the list.

itemCount is the length of the list to be built.

itemBuilder is a simple callback provided by you that is called to build every item.

This is what it looks like when ran on a device.

ListView also provides another named constructor called ListView.separated. This allows you to also provide a builder for an item separator between two items.

class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView'), ), body: ListView.separated( itemCount: 100, itemBuilder: (context, index) { return Container( padding: EdgeInsets.all(16.0), child: Text('Item #$index'), ); }, separatorBuilder: (context, index) { return Divider(color: Colors.grey); }, ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Home extends StatelessWidget { @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'ListView' ) , ) , body : ListView . separated ( itemCount : 100 , itemBuilder : ( context , index ) { return Container ( padding : EdgeInsets . all ( 16.0 ) , child : Text ( 'Item #$index' ) , ) ; } , separatorBuilder : ( context , index ) { return Divider ( color : Colors . grey ) ; } , ) , ) ; } }

separatorBuilder is called between every two items. Let’s say you have a list of 2 Items. So first itemBuilder will be called to get the first Item (#1) then separatorBuilder is called to get the separator and finally itemBuilder is called again to build the second Item (#2). So if you have N number of items, the separatorBuilder will be called N-1 number of times. We are using Flutter’s out of the box Divider widget as our separator between items.

Let’s give a different background colour to every other item in the list.

ListView Flutter Background Color class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView'), ), body: ListView.builder( itemCount: 100, itemBuilder: (context, index) { return Container( padding: EdgeInsets.all(16.0), child: Text('Item #$index'), color: index % 2 == 0 ? Colors.grey[200] : Colors.white, ); }, ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Home extends StatelessWidget { @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'ListView' ) , ) , body : ListView . builder ( itemCount : 100 , itemBuilder : ( context , index ) { return Container ( padding : EdgeInsets . all ( 16.0 ) , child : Text ( 'Item #$index' ) , color : index % 2 == 0 ? Colors . grey [ 200 ] : Colors . white , ) ; } , ) , ) ; } }

Basics of Routing

Till now you have been displaying data on a single screen. Let’s expand our horizons and learn how to launch a new page.

Let’s prepare our Home widget to open up a new page. We will add a simple button, which when clicked will open our new page. Remove the ListView for now, we will add it back later.

Home - Flutter class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView'), ), body: Center( child: RaisedButton( child: Text('Open Second Page'), onPressed: () {}, ), ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Home extends StatelessWidget { @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'ListView' ) , ) , body : Center ( child : RaisedButton ( child : Text ( 'Open Second Page' ) , onPressed : ( ) { } , ) , ) , ) ; } }

You can write the code for second page in the same main.dart file, but I don’t want you to do that. Let’s be good devs, create a new file named second_page.dart and write the code in it.

As you know everything in Flutter is a Widget, so is our new page. It’s just another “Widget”.

second_page.dart class SecondPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Second Page'), ), body: Center( child: Text('Second Page'), ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 class SecondPage extends StatelessWidget { @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'Second Page' ) , ) , body : Center ( child : Text ( 'Second Page' ) , ) , ) ; } }

Never miss a post from TheTechnoCafe

Home Widget class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView'), ), body: Center( child: RaisedButton( child: Text('Open Second Page'), onPressed: () { Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) { return SecondPage(); }, ), ); }, ), ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Home extends StatelessWidget { @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'ListView' ) , ) , body : Center ( child : RaisedButton ( child : Text ( 'Open Second Page' ) , onPressed : ( ) { Navigator . of ( context ) . push ( MaterialPageRoute ( builder : ( BuildContext context ) { return SecondPage ( ) ; } , ) , ) ; } , ) , ) , ) ; } }

You might feel alienated looking at this code, but don’t worry, it’s quite simple. Let’s break it down.

Navigator : Gives you the functionality to open/close pages in Flutter, and various methods related to managing pages. I highly encourage you to take a look at the Navigator documentation to learn more and play around.

: Gives you the functionality to open/close pages in Flutter, and various methods related to managing pages. I highly encourage you to take a look at the to learn more and play around. MaterialPageRoute: Navigator takes something called Route. MaterialPageRoute is an implementation of it. All it does it provides you with beautiful default transition animations and other Material goodness. In the builder property of MaterialPageRoute you return your SecondPage widget, which is what you want to build in the new page! Your widget is essentially “wrapped” in a PageRoute. You can extend one of the PageRoute or PageRouteBuilder to provide your own custom transitions, padding, background colour and other cool stuff.

Run the app, press the button and watch the second page in action!

Now let’s bring our ListView back in our Home widget, we will open the second page on click of any item in the List. To add tap functionality, let us use GestureDetector. Wrap the Container with a GestureDetector.

class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView'), ), body: ListView.builder( itemCount: 100, itemBuilder: (context, index) { return GestureDetector( onTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) { return SecondPage(); }, ), ); }, child: Container( padding: EdgeInsets.all(16.0), child: Text('Item #$index'), color: index % 2 == 0 ? Colors.grey[200] : Colors.white, ), ); }, ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Home extends StatelessWidget { @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'ListView' ) , ) , body : ListView . builder ( itemCount : 100 , itemBuilder : ( context , index ) { return GestureDetector ( onTap : ( ) { Navigator . of ( context ) . push ( MaterialPageRoute ( builder : ( context ) { return SecondPage ( ) ; } , ) , ) ; } , child : Container ( padding : EdgeInsets . all ( 16.0 ) , child : Text ( 'Item #$index' ) , color : index % 2 == 0 ? Colors . grey [ 200 ] : Colors . white , ) , ) ; } , ) , ) ; } }

Click on any item and second page will pop up. Hmmm, let’s do something more exciting, let’s pass some data to second page, particularly, pass the index of clicked item to the next page. Well there is not magic, nothing like Intent or anything (if you are from an Android background), data can be passed simply with constructor args.

Modify the SecondPage widget to take an integer.

second_page.dart class SecondPage extends StatelessWidget { final int clickedIndex; const SecondPage(this.clickedIndex); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Second Page'), ), body: Center( child: Text('Clicked Index is: $clickedIndex'), ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class SecondPage extends StatelessWidget { final int clickedIndex ; const SecondPage ( this . clickedIndex ) ; @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'Second Page' ) , ) , body : Center ( child : Text ( 'Clicked Index is: $clickedIndex' ) , ) , ) ; } }

In Home widget, modify to pass in the current clicked in index.

class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView'), ), body: ListView.builder( itemCount: 100, itemBuilder: (context, index) { return GestureDetector( onTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) { return SecondPage(index); }, ), ); }, child: Container( padding: EdgeInsets.all(16.0), child: Text('Item #$index'), color: index % 2 == 0 ? Colors.grey[200] : Colors.white, ), ); }, ), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Home extends StatelessWidget { @ override Widget build ( BuildContext context ) { return Scaffold ( appBar : AppBar ( title : Text ( 'ListView' ) , ) , body : ListView . builder ( itemCount : 100 , itemBuilder : ( context , index ) { return GestureDetector ( onTap : ( ) { Navigator . of ( context ) . push ( MaterialPageRoute ( builder : ( context ) { return SecondPage ( index ) ; } , ) , ) ; } , child : Container ( padding : EdgeInsets . all ( 16.0 ) , child : Text ( 'Item #$index' ) , color : index % 2 == 0 ? Colors . grey [ 200 ] : Colors . white , ) , ) ; } , ) , ) ; } }

Click on any item!

Next Tutorial – Flutter Crash Course – 6 – Networking Basics >>

<< Previous Tutorial – Flutter Crash Course – 4 – Dive into more Flutter Widgets