How to use TabBar in Flutter

We use TabBar inside the AppBar in Flutter. In this section, we’ll learn how to set a TabBar inside Flutter AppBar and we’ll also learn how to use TabBar.

In general, when we select a tab, it displays some content or a page. Just like the following screenshot.

Home tab is selected and displays the Home page
Home tab is selected and displays the Home page

We’ve created tabs using the TabBar widget. As we can see in the above screenshot, we’ve created four tabs and each tab will display different page.

Now this page might be not as simple as we’ve shown in this example. Each page, or screen of any Flutter application should have a unique identity that we’re also going to learn as we progress.

Let’s try to understand the inside mechanism. After that, we’ll see the code.

Firstly, any TabBar needs a TabBarView widget to display different pages.

Although before that, when a tab is selected, the TabBar widget always looks up and tries to find the nearest DefaultTabController.

Basically, the TabController is created by the DefaultTabController. Because of that reason, we wrap the Scaffold widget by DefaultTabController.

Sitting at the top, the DfaultTabController maintains the synchronization between tab and content. That’s why, it asks how many tabs we’re going to create. The length property sets the value.

As a result, when we select a tab, only related page is opened up in the body section. We’ve clicked the Log in tab, therefore the Log in page has popped up.

Tab controller keeps tab and content in sync
Tab controller keeps tab and content in sync

Let’s take a look at the code snippet where we’ve defined these properties.

import 'package:flutter/material.dart';

//import 'all_pages.dart';

/// adding transparent appbar
/// modifying build icons

class DashBoardHome extends StatelessWidget {
  const DashBoardHome({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //var size = MediaQuery.of(context).size;
    return DefaultTabController(
      length: 4,
      child: Scaffold(
        appBar: AppBar(
          centerTitle: true,

          //backgroundColor: Colors.grey[400],
          flexibleSpace: Container(
            decoration: const BoxDecoration(
              gradient: LinearGradient(
                colors: [
                  Colors.pink,
                  Colors.grey,
                ],
                begin: Alignment.topRight,
                end: Alignment.bottomRight,
              ),
            ),
          ),
          elevation: 20,
          titleSpacing: 80,
          leading: const Icon(Icons.menu),
          title: const Text(
            'Let\'s Go!',
            textAlign: TextAlign.center,
          ),
          actions: [
            buildIcons(
              const Icon(Icons.add_a_photo),
            ),
            buildIcons(
              const Icon(
                Icons.notification_add,
              ),
            ),
            buildIcons(
              const Icon(
                Icons.settings,
              ),
            ),
            buildIcons(
              const Icon(Icons.search),
            ),
          ],
          bottom: const TabBar(
            isScrollable: true,
            indicatorColor: Colors.red,
            indicatorWeight: 10,
            tabs: [
              Tab(
                icon: Icon(
                  Icons.home,
                ),
                text: 'Home',
              ),
              Tab(
                icon: Icon(
                  Icons.panorama_fish_eye,
                ),
                text: 'Log in',
              ),
              Tab(
                icon: Icon(
                  Icons.settings,
                ),
                text: 'Settings',
              ),
              Tab(
                icon: Icon(
                  Icons.local_activity,
                ),
                text: 'Location',
              ),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            newPage('Home'),
            newPage('Log in'),
            newPage('Settings'),
            newPage('Location'),
          ],
        ),
      ),
    );
  }

  IconButton buildIcons(Icon icon) {
    return IconButton(
      onPressed: () {},
      icon: icon,
    );
  }

  Widget newPage(String text) => Center(
        child: Text(
          text,
          style: const TextStyle(
            fontSize: 60,
            fontWeight: FontWeight.bold,
            color: Colors.red,
          ),
        ),
      );
}

For the full code, please visit the concerned GitHub repository.

The above code is quite simple. We’ve wrapped the Scaffold widget with default tab controller and set the length to 4. It means, we can keep four tabs inside TabBar and four pages inside TabBarView widget.

Exactly that happens in the above code.

bottom: const TabBar(
            isScrollable: true,
            indicatorColor: Colors.red,
            indicatorWeight: 10,
            tabs: [
              Tab(
                icon: Icon(
                  Icons.home,
                ),
                text: 'Home',
              ),
              Tab(
                icon: Icon(
                  Icons.panorama_fish_eye,
                ),
                text: 'Log in',
              ),
              Tab(
                icon: Icon(
                  Icons.settings,
                ),
                text: 'Settings',
              ),
              Tab(
                icon: Icon(
                  Icons.local_activity,
                ),
                text: 'Location',
              ),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            newPage('Home'),
            newPage('Log in'),
            newPage('Settings'),
            newPage('Location'),
          ],
        ),
      ),
....

Here DefaultTabController has created a Tab Controller and makes it available to all descendant widgets.

As a result, we can set the other properties of TabBar as well.

 bottom: const TabBar(
            isScrollable: true,
            indicatorColor: Colors.red,
            indicatorWeight: 10,
...

We can add more tabs and TabBarView pages. Because we have set the “isScrollable” property true. Moreover, indicator color, and indicator height to a certain value. Consequently, when we click the tab, it’s highlighted.

The job of DefaultTabController is to share a TabController with a TabBar or a TabBarView. No exception takes place here. It does its job, and the tab and content are in complete sync.

Last but not least. One caveat before we close down this topic.

Since TabBar works at tandem with TabBarView widget, and pages – to be shown – are maintained by TabBarView, we need not use Icon Button widget inside the TabBar. That’ll throw a render overflow error.

Why?

The reason is quite logical. The TabBar here just shows the icons. It does not allow those icons to pass a callback.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Technical blog

Twitter

Comments

One response to “How to use TabBar in Flutter”

  1. […] widget that has a required parameter length which decides how many tabs we should use in TabBar widget. Moreover, according to that length mentioned we need to return the same number of pages in […]

Leave a Reply