Working with Tabbed Navigation in Flutter

Tabbed navigation is a common UI pattern that allows users to navigate between different views or sections within an app. In Flutter, implementing tabbed navigation is straightforward thanks to widgets like TabBar and TabBarView. This comprehensive guide explores how to effectively use tabbed navigation in Flutter, complete with detailed explanations and code examples.

What is Tabbed Navigation?

Tabbed navigation divides an app’s screen into different tabs, each representing a unique view or section. This allows users to switch between these views effortlessly with a simple tap. Tabbed navigation is often implemented using a TabBar to display the tabs and a TabBarView to show the corresponding content.

Why Use Tabbed Navigation?

  • Improved User Experience: Simplifies navigation by presenting options clearly.
  • Content Organization: Divides content into logical, manageable sections.
  • Efficiency: Allows users to quickly access different parts of the app.

How to Implement Tabbed Navigation in Flutter

Implementing tabbed navigation in Flutter involves using the TabBar and TabBarView widgets. Here’s a step-by-step guide:

Step 1: Set Up a TabController

The TabController is responsible for managing the state of the TabBar and TabBarView. It keeps track of which tab is currently selected and updates the view accordingly.


import 'package:flutter/material.dart';

class TabbedNavigationExample extends StatefulWidget {
  @override
  _TabbedNavigationExampleState createState() => _TabbedNavigationExampleState();
}

class _TabbedNavigationExampleState extends State<TabbedNavigationExample>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Tabbed Navigation Example'),
        bottom: TabBar(
          controller: _tabController,
          tabs: [
            Tab(text: 'Tab 1'),
            Tab(text: 'Tab 2'),
            Tab(text: 'Tab 3'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          Center(child: Text('Content of Tab 1')),
          Center(child: Text('Content of Tab 2')),
          Center(child: Text('Content of Tab 3')),
        ],
      ),
    );
  }
}

Key points:

  • SingleTickerProviderStateMixin: Used to provide a Ticker for animations, required by the TabController.
  • TabController(length: 3, vsync: this): Initializes the TabController with the number of tabs and a vsync (vertical sync) parameter.
  • dispose(): Disposes of the TabController to free up resources.

Step 2: Create the TabBar

The TabBar widget displays the tabs and handles user taps to switch between tabs. It is typically placed in the AppBar.


TabBar(
  controller: _tabController,
  tabs: [
    Tab(text: 'Tab 1'),
    Tab(text: 'Tab 2'),
    Tab(text: 'Tab 3'),
  ],
)

Explanation:

  • controller: _tabController: Assigns the TabController to the TabBar.
  • tabs: [...]: A list of Tab widgets, each representing a tab.
  • Tab(text: 'Tab 1'): Each Tab contains a text label. Icons or other widgets can also be used.

Step 3: Create the TabBarView

The TabBarView widget displays the content corresponding to the currently selected tab. It should be placed in the body of the Scaffold.


TabBarView(
  controller: _tabController,
  children: [
    Center(child: Text('Content of Tab 1')),
    Center(child: Text('Content of Tab 2')),
    Center(child: Text('Content of Tab 3')),
  ],
)

Explanation:

  • controller: _tabController: Assigns the TabController to the TabBarView.
  • children: [...]: A list of widgets, each corresponding to a tab. The order should match the order of the tabs in the TabBar.
  • Center(child: Text('Content of Tab 1')): Simple example content for each tab. You can replace these with more complex widgets.

Customizing Tabbed Navigation

Flutter provides several ways to customize the appearance and behavior of tabbed navigation.

1. TabBar Properties

The TabBar widget offers properties for customizing its appearance:


TabBar(
  controller: _tabController,
  tabs: [
    Tab(text: 'Tab 1', icon: Icon(Icons.home)),
    Tab(text: 'Tab 2', icon: Icon(Icons.search)),
    Tab(text: 'Tab 3', icon: Icon(Icons.settings)),
  ],
  indicatorColor: Colors.white,
  indicatorWeight: 5.0,
  labelColor: Colors.white,
  unselectedLabelColor: Colors.grey,
)

Key customizations:

  • icon: Adds an icon to each tab.
  • indicatorColor: Sets the color of the tab indicator.
  • indicatorWeight: Sets the thickness of the tab indicator.
  • labelColor: Sets the color of the selected tab’s label.
  • unselectedLabelColor: Sets the color of the unselected tabs’ labels.

2. Styling the TabBarView

The TabBarView typically contains different content for each tab, so you can customize each tab’s content as needed.


TabBarView(
  controller: _tabController,
  children: [
    ListView(
      children: [
        ListTile(title: Text('Item 1')),
        ListTile(title: Text('Item 2')),
        ListTile(title: Text('Item 3')),
      ],
    ),
    Center(child: Text('Content of Tab 2')),
    Center(child: Text('Content of Tab 3')),
  ],
)

Explanation:

  • ListView in Tab 1: Example of using a ListView in the first tab.
  • Different Content for Each Tab: Each tab can have its own unique layout and content.

Example: Complete Tabbed Navigation with Icons and Styling


import 'package:flutter/material.dart';

class StyledTabbedNavigation extends StatefulWidget {
  @override
  _StyledTabbedNavigationState createState() => _StyledTabbedNavigationState();
}

class _StyledTabbedNavigationState extends State<StyledTabbedNavigation>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Styled Tabbed Navigation'),
        bottom: TabBar(
          controller: _tabController,
          tabs: [
            Tab(icon: Icon(Icons.home), text: 'Home'),
            Tab(icon: Icon(Icons.search), text: 'Search'),
            Tab(icon: Icon(Icons.settings), text: 'Settings'),
          ],
          indicatorColor: Colors.white,
          indicatorWeight: 3.0,
          labelColor: Colors.white,
          unselectedLabelColor: Colors.grey,
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          Center(child: Text('Home Content', style: TextStyle(fontSize: 20))),
          Center(child: Text('Search Content', style: TextStyle(fontSize: 20))),
          Center(child: Text('Settings Content', style: TextStyle(fontSize: 20))),
        ],
      ),
    );
  }
}

Conclusion

Tabbed navigation in Flutter is a versatile way to organize and present content within your app. By using the TabBar and TabBarView widgets, along with a TabController, you can create an intuitive and efficient navigation experience for your users. With the ability to customize both the appearance and content of the tabs, you can tailor the navigation to fit your app’s specific design and functional requirements.