Building a Custom AppTabBar in Flutter

In this blog post, we will explore how to create a custom AppTabBar in Flutter using the `TabBar` and `TabController` widgets. A tab bar is a common UI element that allows users to navigate between different sections or views within an app. By building a custom AppTabBar, you can add a personalized touch to your Flutter application and enhance the user experience. We will walk through the code step by step and explain how each component works together to create the desired effect.

Custom_trending_AppTabBar


Code Explanation:

Let's dive into the provided code and understand how to build a custom AppTabBar in Flutter:

First, we import the necessary Flutter classes and widgets:

import 'package:flutter/material.dart';

Next, we define the `MyApp` class, which serves as the entry point for the application:

void main() {
    runApp(const MyApp());
  }
  
  class MyApp extends StatefulWidget {
    const MyApp({Key? key}) : super(key: key);
  
    @override
    _MyAppState createState() => _MyAppState();
  }
  

The `MyApp` class extends `StatefulWidget` and defines the structure of the app. It contains the `build` method, which returns a `MaterialApp` widget:

return MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text('Custom AppTabBar'),
        backgroundColor: Colors.orange,
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          // TabBarView and TabBar will be added here
        ],
      ),
    ),
  );
  

Inside the `body` of the `Scaffold`, we will add the `TabBarView` and `TabBar` widgets to display the tab content and the custom tab bar, respectively.

Now, let's move to the `AppTabBar` class:

class AppTabBar extends StatefulWidget {
    final String tab1;
    final String tab2;
    final String? tab3;
    final TabController controller;
  
    const AppTabBar({
      Key? key,
      required this.tab1,
      required this.tab2,
      this.tab3,
      required this.controller,
    }) : super(key: key);
  
    @override
    _AppTabBarState createState() => _AppTabBarState();
  }
  

The `AppTabBar` class is a `StatefulWidget` that takes three required parameters: `tab1`, `tab2`, and `controller`, and an optional parameter `tab3`. It also defines the `_AppTabBarState` class to manage the state of the widget.

Inside `_AppTabBarState`, we define the `build` method, which returns a custom styled `TabBar` wrapped in a `DecoratedBox`:

class _AppTabBarState extends State<AppTabBar> {
    @override
    Widget build(BuildContext context) {
      var height = MediaQuery.of(context).size.height;
      var width = MediaQuery.of(context).size.width;
      return Flexible(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: SizedBox(
            height: height * 0.07,
            width: width * 0.85,
            child: DecoratedBox(
              decoration: BoxDecoration(
                color: Colors.blueGrey,
                borderRadius: BorderRadius.circular(10),
              ),
              child: TabBar(
                unselectedLabelColor: Colors.black,
                labelColor: Colors.white,
                indicator: BoxDecoration(
                  borderRadius: BorderRadius.circular(10),
                  color: Colors.orange,
                ),
                controller: widget.controller,
                tabs: [
                  Tab(
                    text: widget.tab1,
                  ),
                  Tab(
                    text: widget.tab2,
                  ),
                  if (widget.tab3 != null)
                    Tab(
                      text: widget.tab3!,
                    ),
                ],
              ),
            ),
          ),
        ),
      );
    }
  }
  

In the `build` method, we retrieve the screen's height and width using `MediaQuery` to make the custom tab bar responsive. We then return a `Flexible` widget wrapped in a `Padding` widget to control the size and spacing of the tab bar. The `TabBar` is styled using the provided parameters and is nested inside a `DecoratedBox` to apply a background color and border radius.

Finally, we need to set up the `TabController` and the tab content in the `MyAppState` class:

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
    late TabController _tabController;
  
    @override
    void initState() {
      super.initState();
      _tabController = TabController(length: 3, vsync: this);
    }
  
    @override
    void dispose() {
      _tabController.dispose(); // Dispose of the TabController
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      // ...
      children: [
        Expanded(
          child: TabBarView(
            controller: _tabController,
            children: [
              // Tab 1 content
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Container(
                  color: Colors.red,
                  child: Center(
                    child: Text('Tab 1 Content'),
                  ),
                ),
              ),
              // Tab 2 content
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Container(
                  color: Colors.blue,
                  child: Center(
                    child: Text('Tab 2 Content'),
                  ),
                ),
              ),
              // Tab 3 content
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Container(
                  color: Colors.green,
                  child: Center(
                    child: Text('Tab 3 Content'),
                  ),
                ),
              ),
            ],
          ),
        ),
        AppTabBar(
          tab1: 'Tab 1',
          tab2: 'Tab 2',
          tab3: 'Tab 3',
          controller: _tabController,
        ),
      ],
      // ...
    }
  }
  

Inside the `build` method, we add a `TabBarView` widget as a child of the `Column` widget. The `TabBarView` displays the content of each tab using `Container` widgets with different colors and corresponding labels. We pass the `_tabController` to the `TabBarView` to synchronize the tab selection with the content.

https://www.linkedin.com/in/pradeepkumarradhakrishnan/


Full source code:

import 'package:flutter/material.dart';

    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
      late TabController _tabController;
    
      @override
      void initState() {
        super.initState();
        _tabController = TabController(length: 3, vsync: this);
      }
    
      @override
      void dispose() {
        _tabController.dispose(); // Dispose of the TabController
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('Custom AppTabBar'),
              backgroundColor: Colors.orange,
            ),
            body: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                Expanded(
                  child: TabBarView(
                    controller: _tabController,
                    children: [
                      // Tab 1 content
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Container(
                          color: Colors.red,
                          child: Center(
                            child: Text('Tab 1 Content'),
                          ),
                        ),
                      ),
                      // Tab 2 content
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Container(
                          color: Colors.blue,
                          child: Center(
                            child: Text('Tab 2 Content'),
                          ),
                        ),
                      ),
                      // Tab 3 content
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Container(
                          color: Colors.green,
                          child: Center(
                            child: Text('Tab 3 Content'),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
                AppTabBar(
                  tab1: 'Tab 1',
                  tab2: 'Tab 2',
                  tab3: 'Tab 3',
                  controller: _tabController,
                ),
              ],
            ),
          ),
        );
      }
    }
    
    class AppTabBar extends StatefulWidget {
      final String tab1;
      final String tab2;
      final String? tab3;
      final TabController controller;
    
      const AppTabBar({
        Key? key,
        required this.tab1,
        required this.tab2,
        this.tab3,
        required this.controller,
      }) : super(key: key);
    
      @override
      _AppTabBarState createState() => _AppTabBarState();
    }
    
    class _AppTabBarState extends State<AppTabBar> {
      @override
      void dispose() {
        widget.controller.dispose(); // Dispose of the TabController
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        var height = MediaQuery.of(context).size.height;
        var width = MediaQuery.of(context).size.width;
        return Flexible(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: SizedBox(
              height: height * 0.07,
              width: width * 0.85,
              child: DecoratedBox(
                decoration: BoxDecoration(
                  color: Colors.blueGrey,
                  borderRadius: BorderRadius.circular(10),
                ),
                child: TabBar(
                  unselectedLabelColor: Colors.black,
                  labelColor: Colors.white,
                  //labelStyle: AppStyles.tabTextStyle,
                  indicator: BoxDecoration(
                    borderRadius: BorderRadius.circular(10),
                    color: Colors.orange,
                  ),
                  controller: widget.controller,
                  tabs: [
                    Tab(
                      text: widget.tab1,
                    ),
                    Tab(
                      text: widget.tab2,
                    ),
                    if (widget.tab3 != null)
                      Tab(
                        text: widget.tab3!,
                      ),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    

Conclusion:

Congratulations! You've learned how to build a custom AppTabBar in Flutter. By utilizing the `TabBar` and `TabController` widgets, you can create personalized and visually appealing tab navigation in your Flutter applications. Experiment with customization options, such as colors, fonts, and animations, to make your custom AppTabBar match your app's design and provide an enhanced user experience.

Remember to consider best practices for performance optimization and responsive design when implementing custom UI components in Flutter. By following the steps outlined in this blog post and exploring additional resources, you'll be well-equipped to create engaging and intuitive user interfaces in your Flutter applications.

Comments

Popular posts from this blog

Error Handling in Flutter - Gradle issue

How to Make a Dynamic and Trending ListView with Flutter Widgets?

Understanding API integration with Getx State management