Bottom Navigation Tab

In this article, I have defined How works navigation bottom tab in flutter.

You can Download Source Code via Github.

It is very easy to implement navigation bottom tab in flutter as following simple code

return Scaffold(
        body: _tabs[_selectedTab],
        bottomNavigationBar: BottomNav(
          index: _selectedTab,
          labelStyle: LabelStyle(showOnSelect: true),
          iconStyle: IconStyle(onSelectColor: AppTheme.Colors.flatPurple),
          items: [
            BottomNavItem("lib/assets/images/bookmark.svg", label: 'bookmark'),
            BottomNavItem("lib/assets/images/notification.svg",
                label: 'notification'),
            BottomNavItem("lib/assets/images/home.svg", label: 'home'),
            BottomNavItem("lib/assets/images/controls.svg", label: 'Settings'),
            BottomNavItem("lib/assets/images/user.svg", label: 'user')
          ],
          onTap: (index) {
            setState(() {
              _selectedTab = index;
            });
          },
        ));

We will add redirection tabs as following

final _tabs = [
BookMarkTab(),
NotificationTab(),
HomeTab(),
StatisticsTab(),
ProfileTab(),
];

main.dart

import 'package:education_app/screen/index.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
        statusBarBrightness: Brightness.dark,
        statusBarIconBrightness: Brightness.dark,
        statusBarColor: Colors.transparent));
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Bottom Navigation Tab',
      home: Index(),
    );
  }
}

index.dart

import 'package:education_app/components/bottomNavigationBar.dart';
import 'package:education_app/screen/bottomTabs/bookmarkTab.dart';
import 'package:education_app/screen/bottomTabs/homeTab.dart';
import 'package:education_app/screen/bottomTabs/placeholderTab.dart';
import 'package:education_app/screen/bottomTabs/profileTab.dart';
import 'package:flutter/material.dart';
import 'package:education_app/utils/Theme.dart' as AppTheme;

import 'bottomTabs/notificationTab.dart';
import 'bottomTabs/statisticsTab.dart';

class Index extends StatefulWidget {
  @override
  _IndexState createState() => _IndexState();
}

class _IndexState extends State<Index> {
  int _selectedTab = 2;

  final _tabs = [
    BookMarkTab(),
    NotificationTab(),
    HomeTab(),
    StatisticsTab(),
    ProfileTab(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: _tabs[_selectedTab],
        bottomNavigationBar: BottomNav(
          index: _selectedTab,
          labelStyle: LabelStyle(showOnSelect: true),
          iconStyle: IconStyle(onSelectColor: AppTheme.Colors.flatPurple),
          items: [
            BottomNavItem("lib/assets/images/bookmark.svg", label: 'bookmark'),
            BottomNavItem("lib/assets/images/notification.svg",
                label: 'notification'),
            BottomNavItem("lib/assets/images/home.svg", label: 'home'),
            BottomNavItem("lib/assets/images/controls.svg", label: 'Settings'),
            BottomNavItem("lib/assets/images/user.svg", label: 'user')
          ],
          onTap: (index) {
            setState(() {
              _selectedTab = index;
            });
          },
        ));
  }
}

bottomNavigatonbar.dart

import 'package:flutter/material.dart' as md;
import 'package:flutter_svg/flutter_svg.dart';

final md.Color defaultColor = md.Colors.grey[700];

final md.Color defaultOnSelectColor = md.Colors.blue;

class BottomNav extends md.StatefulWidget {
  final int index;
  final void Function(int i) onTap;
  final List<BottomNavItem> items;
  final double elevation;
  final IconStyle iconStyle;
  final md.Color color;
  final LabelStyle labelStyle;

  BottomNav({
    this.index,
    this.onTap,
    this.items,
    this.elevation = 0.0,
    this.iconStyle,
    this.color = md.Colors.white,
    this.labelStyle,
  })  : assert(items != null),
        assert(items.length >= 2);

  @override
  BottomNavState createState() => BottomNavState();
}

class BottomNavState extends md.State<BottomNav> {
  int currentIndex;
  IconStyle iconStyle;
  LabelStyle labelStyle;

  @override
  void initState() {
    currentIndex = widget.index ?? 0;
    iconStyle = widget.iconStyle ?? IconStyle();
    labelStyle = widget.labelStyle ?? LabelStyle();
    super.initState();
  }

  @override
  md.Widget build(md.BuildContext context) {
    return md.Material(
        elevation: widget.elevation,
        color: widget.color,
        child: md.Row(
          mainAxisAlignment: md.MainAxisAlignment.spaceAround,
          mainAxisSize: md.MainAxisSize.max,
          children: widget.items.map((b) {
            final int i = widget.items.indexOf(b);
            final bool selected = i == currentIndex;

            return BMNavItem(
              icon: b.icon,
              iconSize:
                  selected ? iconStyle.getSelectedSize() : iconStyle.getSize(),
              label: parseLabel(b.label, labelStyle, selected),
              onTap: () => onItemClick(i),
              textStyle: selected
                  ? labelStyle.getOnSelectTextStyle()
                  : labelStyle.getTextStyle(),
              color: selected
                  ? iconStyle.getSelectedColor()
                  : iconStyle.getColor(),
            );
          }).toList(),
        ));
  }

  onItemClick(int i) {
    setState(() {
      currentIndex = i;
    });
    if (widget.onTap != null) widget.onTap(i);
  }

  parseLabel(String label, LabelStyle style, bool selected) {
    if (!style.isVisible()) {
      return null;
    }

    if (style.isShowOnSelect()) {
      return selected ? label : null;
    }

    return label;
  }
}

class BottomNavItem {
  final String icon;
  final String label;

  BottomNavItem(this.icon, {this.label});
}

class LabelStyle {
  final bool visible;
  final bool showOnSelect;
  final md.TextStyle textStyle;
  final md.TextStyle onSelectTextStyle;

  LabelStyle(
      {this.visible,
      this.showOnSelect,
      this.textStyle,
      this.onSelectTextStyle});

  isVisible() {
    return visible ?? true;
  }

  isShowOnSelect() {
    return showOnSelect ?? false;
  }

  // getTextStyle returns `textStyle` with default `fontSize` and
  // `color` values if not provided. if `textStyle` is null then
  // returns default text style
  getTextStyle() {
    if (textStyle != null) {
      return md.TextStyle(
        inherit: textStyle.inherit,
        color: textStyle.color ?? defaultOnSelectColor,
        fontSize: textStyle.fontSize ?? 12.0,
        fontWeight: textStyle.fontWeight,
        fontStyle: textStyle.fontStyle,
        letterSpacing: textStyle.letterSpacing,
        wordSpacing: textStyle.wordSpacing,
        textBaseline: textStyle.textBaseline,
        height: textStyle.height,
        locale: textStyle.locale,
        foreground: textStyle.foreground,
        background: textStyle.background,
        decoration: textStyle.decoration,
        decorationColor: textStyle.decorationColor,
        decorationStyle: textStyle.decorationStyle,
        debugLabel: textStyle.debugLabel,
        fontFamily: textStyle.fontFamily,
      );
    }
    return md.TextStyle(color: defaultColor, fontSize: 12.0);
  }

  // getOnSelectTextStyle returns `onSelectTextStyle` with
  // default `fontSize` and `color` values if not provided. if
  // `onSelectTextStyle` is null then returns default text style
  getOnSelectTextStyle() {
    if (onSelectTextStyle != null) {
      return md.TextStyle(
        inherit: onSelectTextStyle.inherit,
        color: onSelectTextStyle.color ?? defaultOnSelectColor,
        fontSize: onSelectTextStyle.fontSize ?? 12.0,
        fontWeight: onSelectTextStyle.fontWeight,
        fontStyle: onSelectTextStyle.fontStyle,
        letterSpacing: onSelectTextStyle.letterSpacing,
        wordSpacing: onSelectTextStyle.wordSpacing,
        textBaseline: onSelectTextStyle.textBaseline,
        height: onSelectTextStyle.height,
        locale: onSelectTextStyle.locale,
        foreground: onSelectTextStyle.foreground,
        background: onSelectTextStyle.background,
        decoration: onSelectTextStyle.decoration,
        decorationColor: onSelectTextStyle.decorationColor,
        decorationStyle: onSelectTextStyle.decorationStyle,
        debugLabel: onSelectTextStyle.debugLabel,
        fontFamily: onSelectTextStyle.fontFamily,
      );
    }
    return md.TextStyle(color: defaultOnSelectColor, fontSize: 12.0);
  }
}

class IconStyle {
  final double size;
  final double onSelectSize;
  final md.Color color;
  final md.Color onSelectColor;

  IconStyle({this.size, this.onSelectSize, this.color, this.onSelectColor});

  getSize() {
    return size ?? 24.0;
  }

  getSelectedSize() {
    return onSelectSize ?? 24.0;
  }

  getColor() {
    return color ?? defaultColor;
  }

  getSelectedColor() {
    return onSelectColor ?? defaultOnSelectColor;
  }
}

class BMNavItem extends md.StatelessWidget {
  final String icon;
  final double iconSize;
  final String label;
  final void Function() onTap;
  final md.Color color;
  final md.TextStyle textStyle;

  BMNavItem({
    this.icon,
    this.iconSize,
    this.label,
    this.onTap,
    this.color,
    this.textStyle,
  })  : assert(icon != null),
        assert(iconSize != null),
        assert(color != null),
        assert(onTap != null);

  @override
  md.Widget build(md.BuildContext context) {
    return md.Expanded(
        child: md.InkResponse(
      key: key,
      child: md.Padding(
          padding: getPadding(),
          child: md.Column(
              mainAxisSize: md.MainAxisSize.min,
              children: <md.Widget>[
                SvgPicture.asset(
                  icon,
                  height: iconSize,
                  color: color,
                  width: iconSize,
                ),
                md.SizedBox(
                  height: 5,
                ),
                label != null
                    ? md.Container(
                        height: 1,
                        width: iconSize / 1.5,
                        color: color,
                      )
                    : md.Container(
                        height: 1, width: 10, color: md.Colors.transparent)
                // label != null
                //     ? md.Text(label, style: textStyle)
                //     : md.Container()
              ])),
      highlightColor: md.Theme.of(context).highlightColor,
      splashColor: md.Theme.of(context).splashColor,
      radius: md.Material.defaultSplashRadius,
      onTap: () => onTap(),
    ));
  }

  // getPadding returns the padding after adjusting the top and bottom
  // padding based on the fontsize and iconSize.
  getPadding() {
    if (label != null) {
      final double p = ((56 - textStyle.fontSize) - iconSize) / 2;
      return md.EdgeInsets.fromLTRB(0.0, p, 0.0, p);
    }
    return md.EdgeInsets.fromLTRB(
        0.0, (56 - iconSize) / 2, 0.0, (56 - iconSize) / 2);
  }
}

add following lib code in your .yaml file

flutter_svg: ^0.13.1
flutter_icons: ^0.1.4
cached_network_image: 2.0.0-rc

You can Download Source Code via Github.

70 Replies to “Bottom Navigation Tab”

  1. Hi there! I simply would like to offer you a big thumbs up for the great info you’ve got here on this post. I will be coming back to your blog for more soon.

  2. Hi my friend! I wish to say that this post is amazing, nice written and include almost all important infos. I would like to see more posts like this.

  3. I was suggested this blog by my cousin. I am not sure whether this post is written by him as noone else know such detailed about my trouble. You are incredible!Thanks!

  4. Normally I don’t read article on blogs, however I would like to say that this write-up very pressuredme to try and do so! Your writing taste has been surprisedme. Thanks, very great article.

Leave a Reply

Your email address will not be published.