A couple of weeks ago I started learning flutter and set out to create a Cookbook. This article explains the procedure of creating a Listview for the main feed of the cookbook in detail. The data is not stored locally, but on my all-time favorite Realtime Database of Firebase. If you would like to refer to the code base you can find it here https://github.com/Anurag26/components : Disclosure If you have any feedback/suggestions/criticism please let me know in the comments section, Thank you! This article is divided into eight steps and there is a flowchart at the end for reference to the code flow. The Cookbook Feed is a list and each item in the list has two parts: 1. The Food icon 2. The Veg or Non-Veg symbol, name and Preparation time The data for the application is stored in a JSON tree in the form of an array of objects. Here each object has attributes which help describe a particular recipe. The figure below shows an array of six such objects. Step 1: Create a class containing the necessary attributes for the recipes and also declare a constructor for the same. This class is used to define the contents of each ListItem. { foodtitle; iconUrl; PreptimeInMins; uid; vegOrNon; RecipeDetailListItem({ .foodtitle, .iconUrl, .PreptimeInMins, .uid, .vegOrNon}); } class RecipeDetailListItem String String String String String this this this this this Step 2: As we will be working with a list, we need another class with a single attribute and a constructor. The attribute, in this case, will be a List of RecipeDetailListItem as shown below. I have declared both the classes in the same dart file: { <RecipeDetailListItem> recipeList; RecipeList({ .recipeList}); } class RecipeList List this Step 3: Let’s not forget to create the JSON tree with the data and upload it on the firebase. As the free plan allows a single tree in the Realtime Database, it is important to design a flexible architecture. As shown below, the recipes for the feed are stored in a single array called browseRecipes within the object. This will allow me to add more objects in the future if needed within the object. content content How to upload JSON to firebase: https://stackoverflow.com/questions/54159398/how-to-upload-json-file-to-firebase Step 4: After uploading JSON data, it is necessary to make calls from the application to populate the List for the feed. Create a new Dart file for this step. This file will hold the widgets of the feed. 4.1: First, we need to make a reference to the fireplace project, The FirebaseDatabase instance, can be used to get a database . This is a to a specific point within the database tree at which read and write operations may be performed. reference reference ; # the package databaseReference = FirebaseDatabase.instance.reference(); import 'package:firebase_database/firebase_database.dart' import final To use the fireplace in your flutter project refers to https://pub.dev/packages/firebase_database#-installing-tab - 4.2: Second, once we make the call to firebase we will receive a JSON object which needs to be parsed to get the relevant data. Hence, in the two classes created for the ListView, we shall create methods which will help us in doing so. As the initial JSON will be in the array format (array of ) we will pass the data to class which has a List attribute. ReceipeDetailListItem RecipeList In the RecipeList class add the following: RecipeList.fromJSON( < , > json){ RecipeList( recipeList: parserecipes(json) ); } factory Map dynamic dynamic return The factory constructor in the code above will help in returning the instance of the class RecipeList which is nothing but the List of RecipeDetailListItems. The factory ensures that a single instance of the class is in use. The raw data received from firebase is like a map of dynamic: dynamic The attribute will be populated with the help of (key-value pair). recipeList parserecipes(). 4.3: <RecipeDetailListItem> parserecipes(recipeJSON){ rList=recipeJSON[ ] ; } static List var 'browseRecipes' as List In the () method we store the necessary list in a variable called , for our reference to enter into the array from the outer object is shown on line 2 above. parserecipes rList browseRecipes content However, if we return rList as it is we would get an error stating that the var is a List<dynamic> type and not List<RecipeDetailListItem>, hence we must map the above list to the RecipeDetailListItem class type. Before mapping, we must create a method in the RecipeDetailListItem class which will help in returning the instance of the class with all the attributes assigned to the data with parsed values. This instance will be then passed to the list. Each recipe will have one instance stored in the list. 4.4: RecipeDetailListItem.fromJson( < , > parsedJson) { RecipeDetailListItem(foodtitle:parsedJson[ ],iconUrl: parsedJson[ ],PreptimeInMins:parsedJson[ ],uid: parsedJson[ ],vegOrNon:parsedJson[ ]); } factory Map dynamic dynamic return 'Name' 'icon' 'PreptimeInMins' 'uid' 'vegOrNon' The above code should be added to to help return the necessary objects. ReceipeDetailListItem class 4.5: Now finish the method in RecipeList class. The third line helps in mapping the list items to the necessary type and the fourth line returns the list which can be used in the ListView widget. parserecipes() <RecipeDetailListItem> parserecipes(recipeJSON){ rList=recipeJSON[ ] ; <RecipeDetailListItem> recipeList=rList.map((data) => RecipeDetailListItem.fromJson(data)).toList(); recipeList; } static List var 'browseRecipes' as List List //Add this return //And this Step 5: Phew… Now that the classes are ready, we need to make calls to the firebase to retrieve the data, to do that I created a new class called MakeCall(). This call would use the firebase reference and make an asynchronous call to the cloud. { <RecipeDetailListItem> listItems=[]; Future< <RecipeDetailListItem>> firebaseCalls (DatabaseReference databaseReference) { RecipeList recipeList; DataSnapshot dataSnapshot = databaseReference.once(); < , > jsonResponse=dataSnapshot.value[ ][ ]; recipeList = RecipeList.fromJSON(jsonResponse); listItems.addAll(recipeList.recipeList); listItems; } } class MakeCall List List async await Map dynamic dynamic 0 'content' new return The class above is fairly intuitive. The method firebaseCalls(databaseReference) returns the list to be used for the ListView. Step 6: Back in the Stateful widget class, I used the expanded widget with a container to house the ListView. Expanded( child:Container( child: ListView.builder() ) , ), new //ListView, However, as the ListView is populated with data received from an Asynchronous call we will use the You can learn more about the FutureBuilder here: FutureBuilder. https://api.flutter.dev/flutter/widgets/FutureBuilder/FutureBuilder.html Step 7: Inside the stateful Widget declare a Future Builder which will call the asynchronous method firebaseCalls created in Step 5. As shown below, I have used the MakeCall object to call the method and passed the databasereference as the argument. In the FureBuilder, the named parameter consists of the part which returns a future and the is the data which is received after a successful call. future: snapshot We must also account for different cases of the case with a successful connection houses the ListView code as shown. connectionstate, The code below also contains the design of each card. Each card has a icon, Title, Preparation time and Veg/Non-Veg symbol. futureBuilder= FutureBuilder( future: makecall.firebaseCalls(databaseReference), builder: (BuildContext context, AsyncSnapshot snapshot) { (snapshot.connectionState) { ConnectionState.none: Text( ); ConnectionState.waiting: Text( ); : (snapshot.hasError) Text( ); ListView.builder( itemCount: snapshot.data.length, itemBuilder: (BuildContext context, index){ Card( elevation: , child: Padding( padding: EdgeInsets.all( ), child: SizedBox( height: MediaQuery.of(context).size.height* , width: MediaQuery.of(context).size.width, child: Card( elevation: , child: Row( children: <Widget>[ Container( child: Image.network(snapshot.data[index].iconUrl,height: MediaQuery.of(context).size.width* ,width: MediaQuery.of(context).size.width* ,), ), Padding( padding: EdgeInsets.only(left: ,right: ,top: ), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ Container( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Row( children: <Widget>[ condition( )== ? Image.asset( ,height: ,width: ,): Image.asset( ,height: ,width: ), SizedBox(width: ), Text(snapshot.data[index].foodtitle, style: TextStyle(fontWeight: FontWeight.w500, fontSize: ,fontFamily: ),) ], ), SizedBox(height: ), Row( children: <Widget>[ IconTheme( data: IconThemeData( color: Colors.black26), child: Icon(Icons.timer,size: ,), ), Text( ,style: TextStyle(fontWeight: FontWeight.w700,color: Colors.black26),), ], ), ], ) ], ), ), ], ), ), ], ) ) ), ), ); }, ); } }, ); var new // async work switch case return new 'Press button to start' case return new 'Loading....' default if return new 'Error: ' ${snapshot.error} else return int return 0.0 const 0.0 0.15 0 new 0.3 0.3 const 10 5 5 new ' ' ${snapshot.data[index].vegOrNon} true new 'images/non_veg.png' 15 15 new 'images/veg.jpg' 15 15 5 20 'Roboto-Black' 10.0 new new new 20.0 ' minutes' ${snapshot.data[index].PreptimeInMins} Step 8: Finally, we need to replace the ListView.builder inside the expanded widget with the futureBuilder: Expanded( child:Container( child: futureBuilder, ) , ), new The flow chart below sums up the code flow: It took me about two to three days to make this List and I am sure there are better practices for the same and hence I would appreciate any possible feedback. If you enjoyed this story, please do share it! Also, feel free to leave a comment below.