persistent_bottom_nav_bar 1.5.5

  • Readme
  • Changelog
  • Example
  • Installing
  • 96

Persistent Bottom Navigation Bar #

pub package version license github stars

A persistent/static bottom navigation bar for Flutter.

Persistent Behavior

Styles #

NeumorphicNeumorphic without subtitle
neumorphic1neumorphic2
Style1Style7
style1style7
Style3Style5
style3style5
Style6Style8
style6style8

Note: These do not include all style variations #

Features #

  • Highly customizable persistent bottom navigation bar.
  • Ability to push new screens with or without bottom navigation bar.
  • Includes platform specific behavior as an option (specify it in the two navigator functions).
  • 12 styles for the bottom navigation bar (includes BottomNavyBar and Neumorphic style).
  • Includes functions for pushing screen with or without the bottom navigation bar i.e. pushNewScreen() and pushNewScreenWithRouteSettings().
  • Based on flutter's Cupertino(iOS) bottom navigation bar.
  • Can be translucent for a particular tab.
  • Custom styling for the navigation bar. Click here for more information.
  • Handles hardware/software Android back button.

Getting Started #

In your flutter project add the dependency:

dependencies:
  persistent_bottom_nav_bar: any

Persistent bottom navigation bar uses PersistentTabController as its controller. Here is how to declare it:

PersistentTabController _controller;

_controller = PersistentTabController(initialIndex: 0);

The main widget then to be declared is PersistentTabView. NOTE: This widget includes SCAFFOLD (based on CupertinoTabScaffold), so no need to declare it. Following is an example for demonstration purposes:


class MyApp extends StatelessWidget {
  const MyApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return PersistentTabView(
      controller: _controller,
      items: _navBarsItems(),
      screens: _buildScreens(),
      showElevation: true,
      navBarCurve: NavBarCurve.upperCorners,
      confineInSafeArea: true,
      handleAndroidBackButtonPress: true,
      iconSize: 26.0,
      navBarStyle: NavBarStyle.style1, // Choose the nav bar style with this property
      onItemSelected: (index) {
        print(index);
      },
    );
  }
}


    List<Widget> _buildScreens() {
        return [
        HomeScreen(),
        SettingsScreen()
        ];
    }


    List<PersistentBottomNavBarItem> _navBarsItems() {
        return [
        PersistentBottomNavBarItem(
            icon: Icon(CupertinoIcons.home),
            title: ("Home"),
            activeColor: CupertinoColors.activeBlue,
            inactiveColor: CupertinoColors.systemGrey,
        ),
        PersistentBottomNavBarItem(
            icon: Icon(CupertinoIcons.settings),
            title: ("Settings"),
            activeColor: CupertinoColors.activeBlue,
            inactiveColor: CupertinoColors.systemGrey,
        ),
        ];
    }

To push a new screen, use the following functions to control the visibility of bottom navigation bar on a particular screen. Additionally, platform specific behavior can be enabled or disabled from here (disabled by default).

If platform specific is enabled while pushing a new screen, on Android it will push the screen WITHOUT the bottom navigation bar but on iOS it will persist the bottom navigation bar. This is the default behavior specified by each platform.


    pushNewScreen(
        context,
        screen: HomeScreen(),
        platformSpecific: false, // OPTIONAL VALUE. False by default, which means the bottom nav bar will persist
        withNavBar: true, // OPTIONAL VALUE. True by default.
    );


    pushNewScreenWithRouteSettings(
        context,
        settings: RouteSettings(name: HomeScreen.routeName),
        screen: HomeScreen(),
        platformSpecific: false,
        withNavBar: true,
    );

If you are pushing a new modal screen, use the following function:


    pushDynamicScreen(
        context,
        screen: HomeModalScreen(),
        platformSpecific: false,
        withNavBar: true,
    );

Some Useful Tips #

Pop to any screen in the navigation graph for a given tab:

    Navigator.of(context).popUntil((route) {
        return route.settings.name == "ScreenToPopBackTo";
    });

Pop back to first screen in the navigation graph for a given tab:

    Navigator.of(context).popUntil(ModalRoute.withName("/"));
    Navigator.of(context).pushAndRemoveUntil(
    CupertinoPageRoute(
      builder: (BuildContext context) {
        return FirstScreen();
      },
    ),
    (_) => false,
  );

Custom Navigation Bar Styling #

If you want to have your own style for the navigation bar, follow these steps:

  1. Declare your custom widget. Please keep in mind that you will have to handle the function onSelectedItem and the integer selectedIndex yourself to maintain full functionality. Also please note that you can define your own model for the navigation bar item instead of the provided PersistentBottomNavBarItem. See this example below for better understanding:

    
         class CustomNavBarWidget extends StatelessWidget {
             final int selectedIndex;
             final List<PersistentBottomNavBarItem> items; // NOTE: You CAN declare your own model here instead of `PersistentBottomNavBarItem`.
             final ValueChanged<int> onItemSelected;
    
             CustomNavBarWidget(
                 {Key key,
                 this.selectedIndex,
                 @required this.items,
                 this.onItemSelected,});
    
             Widget _buildItem(
                 PersistentBottomNavBarItem item, bool isSelected) {
                 return Container(
                 alignment: Alignment.center,
                 height: 60.0,
                 child: Column(
                     mainAxisAlignment: MainAxisAlignment.center,
                     crossAxisAlignment: CrossAxisAlignment.center,
                     mainAxisSize: MainAxisSize.min,
                     children: <Widget>[
                     Flexible(
                         child: IconTheme(
                         data: IconThemeData(
                             size: 26.0,
                             color: isSelected
                                 ? (item.activeContentColor == null
                                     ? item.activeColor
                                     : item.activeContentColor)
                                 : item.inactiveColor == null
                                     ? item.activeColor
                                     : item.inactiveColor),
                         child: item.icon,
                         ),
                     ),
                     Padding(
                         padding: const EdgeInsets.only(top: 5.0),
                         child: Material(
                         type: MaterialType.transparency,
                         child: FittedBox(
                             child: Text(
                             item.title,
                             style: TextStyle(
                                 color: isSelected
                                     ? (item.activeContentColor == null
                                         ? item.activeColor
                                         : item.activeContentColor)
                                     : item.inactiveColor,
                                 fontWeight: FontWeight.w400,
                                 fontSize: item.titleFontSize),
                         )),
                         ),
                     )
                     ],
                 ),
                 );
             }
    
             @override
             Widget build(BuildContext context) {
                 return Container(
                 color: Colors.white,
                 child: Container(
                     width: double.infinity,
                     height: 60.0,
                     child: Row(
                     mainAxisAlignment: MainAxisAlignment.spaceAround,
                     children: items.map((item) {
                         var index = items.indexOf(item);
                         return Flexible(
                         child: GestureDetector(
                             onTap: () {
                             this.onItemSelected(index);
                             },
                             child: _buildItem(
                                 item, selectedIndex == index),
                         ),
                         );
                     }).toList(),
                     ),
                 ),
                 );
             }
         }
    
    
  2. In the main PersistentTabView widget, set the navBarStyle property as NavBarStyle.custom and pass on the custom widget you just created in the customWidget property like this:

    
     class MyApp extends StatelessWidget {
         const MyApp({Key key}) : super(key: key);
    
         @override
         Widget build(BuildContext context) {
             return PersistentTabView(
             controller: _controller,
             itemCount: items.length, // This is required in case of custom style! Pass the number of items for the nav bar.
             screens: _buildScreens(),
             confineInSafeArea: true,
             handleAndroidBackButtonPress: true,
             onItemSelected: (int) {
                 setState(() {}); // This is required to update the nav bar if Android back button is pressed
             },
             customWidget: CustomNavBarWidget( // Your custom widget goes here
                 items: _navBarsItems(),
                 selectedIndex: _controller.index,
                 onItemSelected: onItemSelected: (index) {
                     setState(() {
                         _controller.index = index; // NOTE: THIS IS CRITICAL!! Don't miss it!
                     });
                 },
             ),
             navBarStyle: NavBarStyle.custom, // Choose the nav bar style with this property
             );
         }
     }
    
    

    NOTE: In the 'onSelected' function of the customWidget, don't forgot to change the index of the controller

  3. Done! As we can see, some of the other properties like iconSize, items are not required here so you can skip those properties. To control the bottom padding of the screen, use bottomScreenPadding. If you give too much bottomScreenPadding but less height in the custom widget or vice versa, layout issues might appear.

For better understanding, refer to the example project in the official git repo.

Changelog #

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[1.5.5] - 2020-05-11 #

  • Added property bottomScreenPadding to control a screen's bottom padding.
  • Added property navBarCurveRadius to change the nav bar curve's radius.
  • Added property popAllScreensOnTapOfSelectedTab to toggle between the ability to pop all pushed screens of a particular selected tab on the second press of the said tab.

[1.5.4] - 2020-05-07 #

  • Fixed background shadow issue when translucency was turned on with showElevation == true.

[1.5.3] - 2020-05-07 #

  • Updated Readme file.

[1.5.2] - 2020-05-07 #

  • Fixed nav bar background color consistency when translucency enabled.
  • Added an example for the navigator function pushDynamicScreen in the sample project.
  • Minor improvements to some styles.

[1.5.1] - 2020-04-30 #

  • Reverted changes to PersistentTabController.

[1.5.0] - 2020-04-30 #

  • Added feature to pop back to first screen on tapping of an already selected tab.
  • Fixed the issue when new tab was added dynamically.
  • Fixed safe area issues.
  • Removed property selectedIndex as it was redundant. Use PersistentTabController to control it instead. Breaking Change
  • Bug fixes.

[1.4.5] - 2020-04-29 #

  • Fixed nav bar translucency for provided styles.

[1.4.4] - 2020-04-29 #

  • Updated dependencies.
  • Removed allCorners value from NavBarCurve as it became redundant after a fix.

[1.4.1] - 2020-04-29 #

  • Improvements to readme.

[1.4.0] - 2020-04-29 #

  • Implemented handling of the Android back button.
  • Fixed the issue where the app would not close at all on Android back button press.
  • Updated navigation bar height to give it the default platform look.
  • Updated styles to fix the issue where a tap would not be registered.

[1.3.0] - 2020-04-25 #

  • Incorporated the much requested ability to customize your own bottom navigation bar widget.
  • Android's back button will no longer close the app.

[1.2.1] - 2020-03-23 #

  • Fixed centering of label text in style 1, 7, 9 and 10.

[1.2.0] - 2020-03-20 #

  • Added navBarHeight and floatingActionWidget properties, some bug fixes and (BREAKING CHANGE) isCurved property is now replaced with navBarCurve which accepts NavBarCurve.

[1.1.5] - 2020-03-04 #

  • Fixed issue for style 6 and 8 where a tap would not be registered occasionally.

[1.1.4] - 2020-03-03 #

  • Bug fixes and improvements for style 6 and 8.

[1.1.3] - 2020-03-02 #

  • Bug fixes.

[1.1.2] - 2020-03-01 #

  • Updated project description.

[1.1.1] - 2020-03-01 #

  • Memory leakage improvements.

[1.1.0] - 2020-03-01 #

  • Added Neumorphic design for the navigation bar.
  • Scale animations for style 7 and 8.
  • More control over translucency.
  • Bug fixes and improvements.

[1.0.15] - 2020-01-27 #

  • bug fixes.

[1.0.14] - 2020-01-27 #

  • Fixed showElevation invisible shadow issue.

[1.0.13] - 2020-01-27 #

  • bug fixes.

[1.0.12] - 2020-01-27 #

  • Increased space between icon and text for most styles (can be reverted by the use of bottomPadding property).

[1.0.11] - 2020-01-27 #

  • bug fixes.

[1.0.10] - 2020-01-26 #

  • bug fixes.

[1.0.9+2] - 2020-01-26 #

  • transparency color improvements.

[1.0.9+1] - 2020-01-26 #

  • bug fixes.

[1.0.9] - 2020-01-26 #

  • Added isTranslucent property for PersistentBottomNavBarItem.
  • Tweaked style8 and style9's magnification.

[1.0.8] - 2020-01-24 #

  • Fixed error thrown if onItemSelected was not declared.
  • Wrapped screens with Material for material elements.

[1.0.7+4] - 2020-01-23 #

  • Updated README file.

[1.0.7+3] - 2020-01-20 #

  • Updated style10's and style7's shadow.

[1.0.7+2] - 2020-01-20 #

  • Updated style10's and style7's shadow.

[1.0.7+1] - 2020-01-20 #

  • Updated style10's borders.

[1.0.7] - 2020-01-20 #

  • Updated style8's text magnification and added new style10.

[1.0.6+1] - 2020-01-20 #

  • Updated navigator functions' arguments BREAKING CHANGE.

[1.0.6] - 2020-01-20 #

  • Updated navigator functions' arguments and added a new nav bar style.

[1.0.5] - 2020-01-18 #

  • Updated return type of navigator functions.

[1.0.4] - 2020-01-16 #

  • Added function for pushing modal screens.

[1.0.3+5] - 2020-01-16 #

  • Updated style8's magnification.

[1.0.3+4] - 2020-01-16 #

  • Updated navigator functions.
  • Added another style for the nav bar.
  • Added horizontalPadding property for the nav bar.

[1.0.3+3] - 2020-01-10 #

  • Fixed issue with bottomPadding.

[1.0.3+2] - 2020-01-09 #

  • Updated pushNewScreen functions.

[1.0.3+1] - 2020-01-09 #

  • Updated project description.

[1.0.3] - 2020-01-09 #

  • Updated font sizes. Added 'bottomPadding` property for navigation bar items.

[1.0.2+1] - 2020-01-09 #

  • Fixes in pushNewScreen.

[1.0.2] - 2020-01-09 #

  • Fixes in pushNewScreen.

[1.0.1] - 2020-01-09 #

  • Updated package's description.

[1.0.0] - 2020-01-09 #

  • Stable version released.

[0.0.5] - 2020-01-09 #

  • Fixed formatting.

[0.0.4] - 2020-01-09 #

  • Example project added to repository.

[0.0.3] - 2020-01-08 #

  • Updated README.md

[0.0.2] - 2020-01-08 #

  • Updated README.md

[0.0.1] - 2020-01-08 #

Added #

  • Persistent Bottom Navigation.
  • Ability to push new screen with or without bottom navigation bar.
  • 8 styles for the bottom navigation bar (includes BottomNavyBar style).
  • Includes function for pushing screen with or without the bottom navigation bar i.e. pushNewScreen() and pushNewScreenWithRouteSettings().
  • Includes platform specific behavior as an option (specify it in the two navigator functions).
  • Based on flutter's Cupertino(iOS) bottom navigation bar.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
import 'custom-widget.dart';
import 'screens.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Persistent Bottom Navigation Bar example project',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {
  PersistentTabController _controller;

  @override
  void initState() {
    super.initState();
    _controller = PersistentTabController(initialIndex: 0);
  }

  List<Widget> _buildScreens() {
    return [
      HomeScreen(),
      HomeScreen(),
      HomeScreen(),
      HomeScreen(),
    ];
  }

  List<PersistentBottomNavBarItem> _navBarsItems() {
    return [
      PersistentBottomNavBarItem(
        icon: Icon(Icons.home),
        title: ("Home"),
        activeColor: Colors.blue,
        inactiveColor: Colors.grey,
        isTranslucent: false,
      ),
      PersistentBottomNavBarItem(
        icon: Icon(Icons.search),
        title: ("Search"),
        activeColor: Colors.teal,
        inactiveColor: Colors.grey,
        isTranslucent: false,
      ),
      PersistentBottomNavBarItem(
        icon: Icon(Icons.message),
        title: ("Chat"),
        activeColor: Colors.deepOrange,
        inactiveColor: Colors.grey,
        isTranslucent: false,
      ),
      PersistentBottomNavBarItem(
        icon: Icon(Icons.settings),
        title: ("Settings"),
        activeColor: Colors.indigo,
        inactiveColor: Colors.grey,
        isTranslucent: false,
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return PersistentTabView(
        controller: _controller,
        screens: _buildScreens(),
        items:
            _navBarsItems(), // Redundant here but defined to demonstrate for other than custom style
        confineInSafeArea: true,
        backgroundColor: Colors.white,
        handleAndroidBackButtonPress: true,
        onItemSelected: (int) {
          setState(
              () {}); // This is required to update the nav bar if Android back button is pressed
        },
        customWidget: CustomNavBarWidget(
          items: _navBarsItems(),
          onItemSelected: (index) {
            setState(() {
              _controller.index = index; // THIS IS CRITICAL!! Don't miss it!
            });
          },
          selectedIndex: _controller.index,
        ),
        itemCount: 4,
        navBarStyle:
            NavBarStyle.custom // Choose the nav bar style with this property
        );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  persistent_bottom_nav_bar: ^1.5.5

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:persistent_bottom_nav_bar/models/neumorphic-properties.widget.dart';
import 'package:persistent_bottom_nav_bar/models/persisten-bottom-nav-item.widget.dart';
import 'package:persistent_bottom_nav_bar/models/persistent-bottom-nav-bar-styles.widget.dart';
import 'package:persistent_bottom_nav_bar/models/persistent-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/models/persistent-nav-bar-scaffold.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/neumorphic-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/simple-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-1-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-10-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-2-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-3-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-4-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-5-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-6-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-7-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-8-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/style-9-bottom-nav-bar.widget.dart';
import 'package:persistent_bottom_nav_bar/nav-bar-styles/styles.dart';
import 'package:persistent_bottom_nav_bar/neumorphic-package-by-serge-software/neumorphic-card.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.widget.dart';
import 'package:persistent_bottom_nav_bar/utils/functions.utils.dart';
import 'package:persistent_bottom_nav_bar/utils/utils.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
92
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
96
Learn more about scoring.

We analyzed this package on Jul 11, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.14
  • Flutter: 1.17.5

Analysis suggestions

Package not compatible with SDK dart

Because:

  • persistent_bottom_nav_bar that is a package requiring null.

Package not compatible with runtime flutter-web on web

Because:

  • package:persistent_bottom_nav_bar/models/neumorphic-properties.widget.dart that imports:
  • package:persistent_bottom_nav_bar/persistent-tab-view.dart that imports:
  • dart:io

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.12 1.14.13
meta 1.1.8 1.2.2
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
vector_math 2.0.8 2.1.0-nullsafety
Dev dependencies
flutter_test