Flutter - Animated tab from scratch reference Uplabs.

Flutter Animated Tab



I have created an animated tab in Flutter, reference taken from Uplabs.
To make the code look clean I have used Animator library for a beautiful animation.
Add this library to your pubspec.yaml file and hit command "flutter packages get" to install the library.

I have created a class TabModel to structure the tab data, don't worry I will show the use of TabModel class. As of now just create file tab_model.dart inside lib/tab folder.

tab_model.dart
import 'package:flutter/widgets.dart';

class TabModel {
  String title;
  Icon icon;
  bool selected;
  TabModel({ this.title,  this.icon, this.selected = false});
}
Now we are ready to prepare tab data with the custom parameter, add the following code inside main.dart file.

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_animated_tab/tab/animated_tab.dart';
import 'package:flutter_animated_tab/tab/tab_model.dart';

void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    home: Home(),
  ));
}

class Home extends StatefulWidget {
  
  HomeState createState() {
    return new HomeState();
  }
}

class HomeState extends State<Home> {
  final List<TabModel> tabModelList = [
    TabModel(
      title: 'Home',
      selected: true,
      icon: Icon(
        Icons.home,
        color: Colors.white,
      ),
    ),
    TabModel(
      title: 'Search',
      icon: Icon(
        Icons.search,
        color: Colors.white,
      ),
    ),
    TabModel(
      title: 'Cart',
      icon: Icon(
        Icons.shopping_cart,
        color: Colors.white,
      ),
    ),
    TabModel(
      title: 'Gift',
      icon: Icon(
        Icons.card_giftcard,
        color: Colors.white,
      ),
    ),
  ];
  String initialWidget = "Home";
  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Column(
        children: <Widget>[
          Expanded(
            child: Container(
              color: Colors.white,
              child: Center(
                child: Text(
                  initialWidget,
                  style: TextStyle(
                    color: Colors.black54,
                    fontFamily: 'Bold',
                    fontSize: 18,
                  ),
                ),
              ),
            ),
          ),
          AnimatedTab(
            tabModelList: tabModelList,
            getCallback: (index) {
              
              setState(() {
                initialWidget = tabModelList[index].title;
              });
            },
          )
        ],
      ),
    );
  }
}
As you can see the above code, I have created List<TabModel> to use in AnimatedTab widget. I have created a custom list with tab model class. Now I want my first tab to be selected so for that I set selected: true in the list tab model, you can choose your selected tab as per your choice.

I have taken a string named initialWidget, you can replace string with any widget that you want to display on tab change.
Now let see the AnimatedTab widget class. Create a file animated_tab.dart inside lib/tab folder.

animated_tab.dart
import 'package:flutter/material.dart';
import 'package:flutter_animated_tab/tab/tab_model.dart';
import 'package:animator/animator.dart';

class AnimatedTab extends StatefulWidget {
  final List<TabModel> tabModelList;
  final Function getCallback;
  AnimatedTab({ this.tabModelList, this.getCallback});
  
  
  _AnimatedTabState createState() => _AnimatedTabState();
}

class _AnimatedTabState extends State<AnimatedTab> {
  int lastSelectedIndex = 0;
  
  Widget build(BuildContext context) {
    return Container(
      height: 60,
      color: Colors.deepOrange,
      child: Stack(
        children: <Widget>[
          Container(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: widget.tabModelList
                  .map(
                    (f) => Center(
                          child: Text(
                            f.title,
                            style: TextStyle(
                              fontFamily: 'Bold',
                              fontSize: 16,
                              color: Colors.white,
                            ),
                          ),
                        ),
                  )
                  .toList(),
            ),
          ),
          Container(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: widget.tabModelList
                  .map(
                    (f) => f.selected
                        ? Animator(
                            cycles: 1,
                            triggerOnInit: true,
                            curve: Curves.fastOutSlowIn,
                            duration: Duration(milliseconds: 400),
                            tween: Tween<double>(begin: -1, end: 0),
                            builder: (anim) => Transform(
                                  transform: Matrix4.translationValues(
                                    0,
                                    -anim.value * 60,
                                    0,
                                  ),
                                  child: Container(
                                    width: MediaQuery.of(context).size.width /
                                        widget.tabModelList.length,
                                    height: 60,
                                    child: f.icon,
                                    color: Colors.deepOrange,
                                  ),
                                ),
                          )
                        : InkWell(
                            child: Container(
                              width: MediaQuery.of(context).size.width /
                                  widget.tabModelList.length,
                              height: 60,
                              color: Colors.transparent,
                            ),
                            onTap: () {
                              setState(() {
                                widget.tabModelList[lastSelectedIndex]
                                    .selected = false;
                                widget
                                    .tabModelList[
                                        widget.tabModelList.indexOf(f)]
                                    .selected = true;
                                lastSelectedIndex =
                                    widget.tabModelList.indexOf(f);
                              });
                              widget
                                  .getCallback(widget.tabModelList.indexOf(f));
                            },
                          ),
                  )
                  .toList(),
            ),
          )
        ],
      ),
    );
  }
}
Let understand the above code.
I have passed tab list and callback function from main.dart to AnimatedTab widget. Tab list data is used to create tab and the callback function is used to change the widget when the user clicks on a tab, the callback function gets trigger when someone clicks on any tab and click will be passed to main.dart file to change the widget.

Now let move further.
In the above design, I have taken the Stack widget to build the tab, inside stack widget I have taken 2 Row widget.
First-row widget is used to display the tab text and the second-row widget is used to display the icon if someone clicks on the tab name then the icon will be displayed.
I have used the Animator library to animate the icon when the tab is clicked. You can change animation as per your choice, I have taken this animation reference from Uplabs.

I hope you like the tab animation example, don't forget to share.

Thank you for reading.