Listview is one of the most basic and most used component in mobile application development. Almost all modern apps use lists in different forms. In this article we will take a lock at how to use a list view and how to sync it with Tabbar layout for ultimate UI experience.

Prerequisites:

  • Basic knowledge of is necessary (as this is not a flutter beginners guide).
  • Installed and setup flutter SDK.
  • In this guide we will be using VS Code.

Getting Started:

Creating our project:

To create a new project, type in cmd.

flutter create --org com.techluts tabbar_app

after creating new project. Open it in VS Code.

flutter folder hierarchy

Here you will find some files and folders that are created by default from flutter SDK.

Navigate to lib>main.dart . Remove the default boilerplate code and paste following:

import 'package:flutter/material.dart';

void main() {
  runApp(MainScreen());
}

class MainScreen extends StatefulWidget {
  MainScreen({Key? key}) : super(key: key);

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

In this code we are creating a Statefull Widget called MainScreen. This will contain tabs and listviews.

To create a tab bar layout we need to wrap Scaffold with DefaultTabController() widget class. _MainScreenState class will look like

class _MainScreenState extends State<MainScreen> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3,
        child: Scaffold(appBar: AppBar(
          title: Text("TabBar App"),
          )
        ),
      ),
    );
  }
}

DefaultTabController have two required attributes:

  • length (defines how many tabs are being displayed)
  • child (Child widget wrapping tabs )

Creating Tabs:

Tabs are the most important components for us because our app will relay on them. So lets start creating tabs.

To create a tabbar on top of screen we need to use TabBar() widget class that will contain all tabs. To do so we need to use bottom attribute of AppBar class.

Scaffold(
          appBar: AppBar(
          title: Text("TabBar App"),
          bottom: const TabBar(
            tabs: [
              Tab(icon: Icon(Icons.directions_car)),
              Tab(icon: Icon(Icons.directions_transit)),
              Tab(icon: Icon(Icons.directions_bike)),
            ]
            ),
          )
        ),

As a result of this code, tabs will start showing and can circulate through them.

tabsr in flutter

To add bind screens with these tabs. We will need another class widget called TabBarView

Scaffold(
          appBar: AppBar(
          title: Text("TabBar App"),
          bottom: const TabBar(
            tabs: [
              Tab(icon: Icon(Icons.directions_car)),
              Tab(icon: Icon(Icons.directions_transit)),
              Tab(icon: Icon(Icons.directions_bike)),
            ]
            ),
          ),
          body:  const TabBarView(
            children: [
              Icon(Icons.directions_car),
              Icon(Icons.directions_transit),
              Icon(Icons.directions_bike),
            ],
          ),
        ),

Congratulations we have successfully created our Tab bar layout, that most of modern apps use in common. Now app is looking something like:

tabs-flutter

Its time to add a ListView instead of Icons.

Adding ListView:

In place of three icons we will create three listviews with different data. We can either create them in separate files. This will help in increasing code readability and management. But for the sack of simplicity we are using only one file main.dart.

So we are going to create a reusable list widget using ListView.builder() class. This will look like following:

class ListWidget extends StatelessWidget {
  Icon ic = const Icon(Icons.abc);
  ListWidget(this.ic, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<String> list = [
      "item1",
      "item2",
      "item3",
      "item4",
      "item5",
      "item6",
      "item7",
      "item8"
    ];
    return ListView.builder(
        itemCount: list.length,
        itemBuilder: ((context, index) {
          return Card(
            child: ListTile(
              leading: ic,
              title: Text(list[index]),
            ),
          );
        }));
  }
}

Lets understand this code.

Here we are using custom widget with class name ListWidget. This widget is accepting a Icon as a parameter. Once icon is received this will be passed to ListTile() widget in Card() widget. If you are not familiar with these widgets you can view documentation of card class and ListTile class.

Finally we have completed our project and our resutlts look something like this:

ListIView + Tabs
import 'package:flutter/material.dart';

void main() {
  runApp(const MainScreen());
}

class MainScreen extends StatefulWidget {
  const MainScreen({Key? key}) : super(key: key);

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            title: const Text("TabBar App"),
            bottom: const TabBar(tabs: [
              Tab(icon: Icon(Icons.directions_car)),
              Tab(icon: Icon(Icons.directions_transit)),
              Tab(icon: Icon(Icons.directions_bike)),
            ]),
          ),
          body: TabBarView(
            children: [
              ListWidget(const Icon(Icons.directions_car)),
              ListWidget(const Icon(Icons.directions_transit)),
              ListWidget(const Icon(Icons.directions_bike)),
            ],
          ),
        ),
      ),
    );
  }
}

class ListWidget extends StatelessWidget {
  Icon ic = const Icon(Icons.abc);
  ListWidget(this.ic, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<String> list = [
      "item1",
      "item2",
      "item3",
      "item4",
      "item5",
      "item6",
      "item7",
      "item8"
    ];
    return ListView.builder(
        itemCount: list.length,
        itemBuilder: ((context, index) {
          return Card(
            child: ListTile(
              leading: ic,
              title: Text(list[index]),
            ),
          );
        }));
  }
}

Thanks for reading this article. If you have any queries let me know in the comments.