December 23, 2020

How to use TabController class in Flutter

By Mohit Agrawal

Let’s understand the basics of TabController class and its uses

In this another Flutter Tutorial, we will learn how to use TabController class with TabBar. Basically, we will start first with the TabBar implementation then will move to the Tab Controller.

tab_bar_flutter_3

What is TabController?

As we already know that in the Tab bar, we have more than one tab and each tab will have different contents. So the main job of the TabController is to keep the tab and its content in sync.

Tab bar comes with a default tab controller which is DefaultTabController. This is the simplest option that you can use for the Tab bar.

But if you want some more customization then you can also go with a custom tab bar controller.

In this article, I will show you the example of both.

  • Default TabController
  • Custom TabController

TabBar with default TabController

To create the tab bar we need three components. Let’s check out them.

1. Create the Tab Controller

Here we will use the DefaultTabController. This default controller we have to set in the MaterialApp widget.

DefaultTabController(
  // The number of tabs / content sections to display.
  length: 2,
  child: // Complete this code in the next step.
);

2. Create the tabs

Let’s create the two tabs as shown in the above image.

DefaultTabController(
  length: 2,
  child: Scaffold(
    appBar: AppBar(
      bottom: TabBar(
        tabs: [
          Tab(icon: Icon(Icons.directions_car)),
          Tab(icon: Icon(Icons.directions_transit)),
        ],
      ),
    ),
  ),
);

3. Create the content for each tab

List<Widget> _tabs = [
    Center(child: Text('You have selected the car !!!')),
    Center(child: Text('Do you like train?'))
  ];

Now assign this list of widgets to the TabBarView.

TabBarView(children: _tabs)

Check out the complete code here.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  List<Widget> _tabs = [
    Center(child: Text('You have selected the car !!!')),
    Center(child: Text('Do you like train?'))
  ];

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
          bottom: TabBar(tabs: [
            Tab(icon: Icon(Icons.directions_car)),
            Tab(icon: Icon(Icons.directions_transit)),
          ],),
        ),
        body: Center(
          child: TabBarView(children: _tabs)
        ),
      ),
    );
  }
}

Run this code and you should get something like this.

tab_bar_flutter_2

TabBar with custom TabController class

In the above example, we have seen how we can use a simple default tab controller and implement the tab bar.

No doubt that it is very simple and easy to use but it has some limitations. Now we are going to discuss one of them.

Why do we need custom tab controller ?

TabBar comes with a callback property i.e onTap(index). This callback returns the index value of the selected tab.

onTap: (index)
{
   // Tab index when user select it, it starts from zero
},

But do you know that if you swipe the view left to right and vice versa then this callback will never be called?

So let’s implement the custom tab controller to over come this limitation.

1. Create custom tab controller

Create a new tab controller variable inside your widget class and initialize it in the initState() as shown in the code snippet.

 TabController _controller;
  void initState() {
    super.initState();
    _controller = TabController(length: 2, vsync: this);
    _controller.addListener(() {
     print(_controller.index);
    });
  }

TabController takes two parameters. This first one is the number of tabs that we want to display.

And the second one is the Vsync property. We use it with the classes which require certain transition or animation to re-render to draw different objects.

Now the other most important thing which we have done is the addListener(). This is a callback like the onTap() but it will called always even if we swipe the tabs.

2. Set the TabController in TabBar

In the above step, we have created our custom Tab Controller. Now let’s see how we can use it in the Tab bar.

Checkout the complete code below.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {

  List<Widget> _tabs = [
    Center(child: Text('You have selected the car !!!')),
    Center(child: Text('Do you like train?'))
  ];

  TabController _controller;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _controller = TabController(length: 2, vsync: this);
    _controller.addListener(() {
     print(_controller.index);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        bottom: TabBar(tabs: [
          Tab(icon: Icon(Icons.directions_car)),
          Tab(icon: Icon(Icons.directions_transit)),
        ],
          onTap: (index) {
            print(index);
          },
          controller: _controller,
        ),
      ),
      body: Center(
        child: TabBarView(children: _tabs, controller: _controller,)
      ),
    );
  }
}

The above code is self explanatory. I hope you enjoyed this article.

Demo

Conclusion

Help me to grow our YouTube Channel: More tutorials like this

I hope this blog post is useful for you, do let me know your opinion in the comment section below.
I will be happy to see your comments down below 👏.
Thanks for reading!!!