Working with Tabbed Navigation Using TabBar and TabView in Flutter

Tabbed navigation is a popular UI pattern for organizing content in mobile and web applications. In Flutter, you can easily implement tabbed navigation using the TabBar and TabView widgets. This approach provides a clean and intuitive way for users to navigate between different sections of your app.

What is Tabbed Navigation?

Tabbed navigation involves dividing content into separate tabs, allowing users to switch between them easily. Each tab typically represents a different view or section of the application, offering a seamless browsing experience.

Why Use Tabbed Navigation?

  • Improved User Experience: Enhances navigation by providing clear and organized content divisions.
  • Efficient Content Management: Simplifies the organization and presentation of multiple content sections.
  • Intuitive Interface: Makes it easy for users to find and access different parts of the application.

How to Implement Tabbed Navigation in Flutter

To implement tabbed navigation in Flutter, follow these steps:

Step 1: Set Up Your Flutter Project

Ensure you have a Flutter project set up. If not, create a new Flutter project using the following command:

flutter create tabbed_navigation_app
cd tabbed_navigation_app

Step 2: Add a TabBar and TabView

Wrap your Scaffold‘s appBar with a TabBar and the body with a TabView inside a DefaultTabController. Here’s how to do it:


import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tabbed Navigation',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: TabbedHomePage(),
    );
  }
}

class TabbedHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 3, // Number of tabs
      child: Scaffold(
        appBar: AppBar(
          title: Text('Tabbed Navigation'),
          bottom: TabBar(
            tabs: [
              Tab(icon: Icon(Icons.home), text: 'Home'),
              Tab(icon: Icon(Icons.search), text: 'Search'),
              Tab(icon: Icon(Icons.settings), text: 'Settings'),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            HomePage(),
            SearchPage(),
            SettingsPage(),
          ],
        ),
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('Home Page Content', style: TextStyle(fontSize: 24)),
    );
  }
}

class SearchPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('Search Page Content', style: TextStyle(fontSize: 24)),
    );
  }
}

class SettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('Settings Page Content', style: TextStyle(fontSize: 24)),
    );
  }
}

Explanation:

  • DefaultTabController: Manages the tab state and synchronizes the TabBar and TabBarView. The length property specifies the number of tabs.
  • TabBar: Displays the tabs in the app bar. Each Tab widget represents a tab and can contain an icon, text, or both.
  • TabBarView: Displays the content corresponding to the selected tab. The children property contains widgets that are displayed based on the active tab index.

Step 3: Customize the TabBar

You can customize the TabBar by changing its appearance and behavior.

Customize TabBar Indicator

To change the color and thickness of the tab indicator, use the indicatorColor and indicatorWeight properties:


TabBar(
  indicatorColor: Colors.white,
  indicatorWeight: 4.0,
  tabs: [
    Tab(icon: Icon(Icons.home), text: 'Home'),
    Tab(icon: Icon(Icons.search), text: 'Search'),
    Tab(icon: Icon(Icons.settings), text: 'Settings'),
  ],
)
Customize Tab Label Style

You can customize the text style for selected and unselected tabs using labelStyle and unselectedLabelStyle:


TabBar(
  labelStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
  unselectedLabelStyle: TextStyle(fontSize: 14),
  tabs: [
    Tab(icon: Icon(Icons.home), text: 'Home'),
    Tab(icon: Icon(Icons.search), text: 'Search'),
    Tab(icon: Icon(Icons.settings), text: 'Settings'),
  ],
)

Step 4: Use a TabController for More Control

For more advanced control, such as programmatically switching tabs, you can use a TabController.

Initialize TabController

Create and initialize a TabController in your StatefulWidget:


import 'package:flutter/material.dart';

class TabbedHomePage extends StatefulWidget {
  @override
  _TabbedHomePageState createState() => _TabbedHomePageState();
}

class _TabbedHomePageState extends State 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'),
        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'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          HomePage(),
          SearchPage(),
          SettingsPage(),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // Switch to the next tab programmatically
          _tabController.animateTo((_tabController.index + 1) % 3);
        },
        child: Icon(Icons.arrow_forward),
      ),
    );
  }
}

Explanation:

  • SingleTickerProviderStateMixin: Used for creating animation controllers.
  • TabController: Initialized in initState with the number of tabs and vsync for animations.
  • dispose: Disposes of the TabController to free up resources.
  • animateTo: Programmatically switches tabs using the controller.

Advanced Tips and Tricks

  • Scrollable Tabs: Use isScrollable: true in TabBar to enable horizontal scrolling for tabs if there are too many to fit on the screen.
  • Custom TabBar Indicators: Implement custom tab indicators using Decoration for more unique designs.
  • Tab Animations: Add custom animations when switching between tabs for enhanced user experience.

Conclusion

Implementing tabbed navigation using TabBar and TabBarView in Flutter is straightforward and provides an efficient way to organize and present content. Whether you’re using a simple setup with DefaultTabController or a more advanced approach with TabController, Flutter offers the tools to create intuitive and visually appealing tabbed interfaces for your applications.