persistent_bottom_nav_bar 6.0.0 persistent_bottom_nav_bar: ^6.0.0 copied to clipboard
A do all, highly customizable persistent/static bottom navigation bar for flutter. Includes up-to 20 styles.
// ignore_for_file: avoid_redundant_argument_values
import "package:flutter/material.dart";
import "package:persistent_bottom_nav_bar/persistent_tab_view.dart";
import "package:persistent_bottom_nav_bar_example_project/animated-icons.screen.dart";
import "package:persistent_bottom_nav_bar_example_project/custom-widget-tabs.widget.dart";
import "package:persistent_bottom_nav_bar_example_project/screens.dart";
void main() => runApp(const MyApp());
BuildContext? testContext;
class MyApp extends StatelessWidget {
const MyApp({final Key? key}) : super(key: key);
@override
Widget build(final BuildContext context) => MaterialApp(
title: "Persistent Bottom Navigation Bar example project",
theme: ThemeData.dark(),
home: const MainMenu(),
initialRoute: "/",
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
"/first": (final context) => const MainScreen2(),
// When navigating to the "/second" route, build the SecondScreen widget.
"/second": (final context) => const MainScreen3(),
},
);
}
class MainMenu extends StatefulWidget {
const MainMenu({final Key? key}) : super(key: key);
@override
_MainMenuState createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
@override
Widget build(final BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text("Sample Project"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: ElevatedButton(
child: const Text("Custom widget example"),
onPressed: () => PersistentNavBarNavigator.pushNewScreen(
context,
screen: CustomWidgetExample(
menuScreenContext: context,
),
),
),
),
const SizedBox(height: 20),
Center(
child: ElevatedButton(
child: const Text("Built-in styles example"),
onPressed: () => PersistentNavBarNavigator.pushNewScreen(
context,
screen: ProvidedStylesExample(
menuScreenContext: context,
),
),
),
),
const SizedBox(height: 20),
Center(
child: ElevatedButton(
child: const Text("Animated icons example"),
onPressed: () => PersistentNavBarNavigator.pushNewScreen(
context,
screen: AnimatedIconScreen(
menuScreenContext: context,
),
),
),
),
],
),
);
}
// ----------------------------------------- Provided Style ----------------------------------------- //
class ProvidedStylesExample extends StatefulWidget {
const ProvidedStylesExample({
required this.menuScreenContext,
final Key? key,
}) : super(key: key);
final BuildContext menuScreenContext;
@override
_ProvidedStylesExampleState createState() => _ProvidedStylesExampleState();
}
class _ProvidedStylesExampleState extends State<ProvidedStylesExample> {
late PersistentTabController _controller;
late bool _hideNavBar;
final List<ScrollController> _scrollControllers = [
ScrollController(),
ScrollController(),
];
NavBarStyle _navBarStyle = NavBarStyle.simple;
@override
void initState() {
super.initState();
_controller = PersistentTabController(initialIndex: 1);
_hideNavBar = false;
}
@override
void dispose() {
for (final element in _scrollControllers) {
element.dispose();
}
super.dispose();
}
List<Widget> _buildScreens() => [
MainScreen(
menuScreenContext: widget.menuScreenContext,
scrollController: _scrollControllers.first,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
onNavBarStyleChanged: (final value) =>
setState(() => _navBarStyle = value),
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
onNavBarStyleChanged: (final value) =>
setState(() => _navBarStyle = value),
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
onNavBarStyleChanged: (final value) =>
setState(() => _navBarStyle = value),
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
onNavBarStyleChanged: (final value) =>
setState(() => _navBarStyle = value),
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
scrollController: _scrollControllers.last,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
onNavBarStyleChanged: (final value) =>
setState(() => _navBarStyle = value),
),
];
Color? _getSecondaryItemColorForSpecificStyles() =>
_navBarStyle == NavBarStyle.style7 ||
_navBarStyle == NavBarStyle.style10 ||
_navBarStyle == NavBarStyle.style15 ||
_navBarStyle == NavBarStyle.style16 ||
_navBarStyle == NavBarStyle.style17 ||
_navBarStyle == NavBarStyle.style18
? Colors.white
: null;
List<PersistentBottomNavBarItem> _navBarsItems() => [
PersistentBottomNavBarItem(
icon: const Icon(Icons.home),
title: "Home",
opacity: 0.7,
activeColorPrimary: Colors.blue,
activeColorSecondary: _navBarStyle == NavBarStyle.style7 ||
_navBarStyle == NavBarStyle.style10
? Colors.white
: null,
inactiveColorPrimary: Colors.grey,
scrollController: _scrollControllers.first,
routeAndNavigatorSettings: RouteAndNavigatorSettings(
initialRoute: "/",
routes: {
"/first": (final context) => const MainScreen2(),
"/second": (final context) => const MainScreen3(),
},
),
),
PersistentBottomNavBarItem(
icon: const Icon(Icons.search),
title: "Search",
activeColorPrimary: Colors.teal,
activeColorSecondary: _navBarStyle == NavBarStyle.style7 ||
_navBarStyle == NavBarStyle.style10
? Colors.white
: null,
inactiveColorPrimary: Colors.grey,
),
PersistentBottomNavBarItem(
icon: const Icon(Icons.add),
title: "Add",
activeColorPrimary: Colors.blueAccent,
inactiveColorPrimary: Colors.grey,
activeColorSecondary: _getSecondaryItemColorForSpecificStyles(),
),
PersistentBottomNavBarItem(
icon: const Icon(Icons.message),
title: "Messages",
activeColorPrimary: Colors.deepOrange,
inactiveColorPrimary: Colors.grey,
activeColorSecondary: _navBarStyle == NavBarStyle.style7 ||
_navBarStyle == NavBarStyle.style10
? Colors.white
: null,
),
PersistentBottomNavBarItem(
icon: const Icon(Icons.settings),
title: "Settings",
activeColorPrimary: Colors.indigo,
inactiveColorPrimary: Colors.grey,
activeColorSecondary: _navBarStyle == NavBarStyle.style7 ||
_navBarStyle == NavBarStyle.style10
? Colors.white
: null,
scrollController: _scrollControllers.last,
),
];
@override
Widget build(final BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text("Navigation Bar Demo"),
backgroundColor: Colors.grey.shade900,
),
drawer: const Drawer(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("This is the Drawer"),
],
),
),
),
body: PersistentTabView(
context,
controller: _controller,
screens: _buildScreens(),
items: _navBarsItems(),
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: false,
stateManagement: true,
hideNavigationBarWhenKeyboardAppears: true,
popBehaviorOnSelectedNavBarItemPress: PopBehavior.once,
hideOnScrollSettings: HideOnScrollSettings(
hideNavBarOnScroll: true,
scrollControllers: _scrollControllers,
),
padding: const EdgeInsets.only(top: 8),
floatingActionButton: IconButton(
icon: Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
shape: BoxShape.circle, color: Colors.orange),
child: const Icon(
Icons.add,
color: Colors.white,
),
),
onPressed: () {},
),
onWillPop: (final context) async {
await showDialog(
context: context ?? this.context,
useSafeArea: true,
builder: (final context) => Container(
height: 50,
width: 50,
color: Colors.white,
child: ElevatedButton(
child: const Text("Close"),
onPressed: () {
Navigator.pop(context);
},
),
),
);
return false;
},
selectedTabScreenContext: (final context) {
testContext = context;
},
backgroundColor: Colors.grey.shade900,
isVisible: !_hideNavBar,
animationSettings: const NavBarAnimationSettings(
navBarItemAnimation: ItemAnimationSettings(
// Navigation Bar's items animation properties.
duration: Duration(milliseconds: 400),
curve: Curves.ease,
),
screenTransitionAnimation: ScreenTransitionAnimationSettings(
// Screen transition animation on change of selected tab.
animateTabTransition: true,
duration: Duration(milliseconds: 300),
screenTransitionAnimationType:
ScreenTransitionAnimationType.fadeIn,
),
onNavBarHideAnimation: OnHideAnimationSettings(
duration: Duration(milliseconds: 100),
curve: Curves.bounceInOut,
),
),
confineToSafeArea: true,
navBarHeight: kBottomNavigationBarHeight,
navBarStyle:
_navBarStyle, // Choose the nav bar style with this property
),
);
}
// ----------------------------------------- Custom Style ----------------------------------------- //
class CustomNavBarWidget extends StatelessWidget {
const CustomNavBarWidget(
this.items, {
required this.selectedIndex,
required this.onItemSelected,
final Key? key,
}) : super(key: key);
final int selectedIndex;
// List<PersistentBottomNavBarItem> is just for example here. It can be anything you want like List<YourItemWidget>
final List<PersistentBottomNavBarItem> items;
final ValueChanged<int> onItemSelected;
Widget _buildItem(
final PersistentBottomNavBarItem item, final bool isSelected) =>
Container(
alignment: Alignment.center,
height: kBottomNavigationBarHeight,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: IconTheme(
data: IconThemeData(
size: 26,
color: isSelected
? (item.activeColorSecondary ?? item.activeColorPrimary)
: item.inactiveColorPrimary ?? item.activeColorPrimary),
child: isSelected ? item.icon : item.inactiveIcon ?? item.icon,
),
),
Padding(
padding: const EdgeInsets.only(top: 5),
child: Material(
type: MaterialType.transparency,
child: FittedBox(
child: Text(
item.title ?? "",
style: TextStyle(
color: isSelected
? (item.activeColorSecondary ??
item.activeColorPrimary)
: item.inactiveColorPrimary,
fontWeight: FontWeight.w400,
fontSize: 12),
)),
),
)
],
),
);
@override
Widget build(final BuildContext context) => Container(
color: Colors.grey.shade900,
child: SizedBox(
width: double.infinity,
height: kBottomNavigationBarHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: items.map((final item) {
final int index = items.indexOf(item);
return Flexible(
child: GestureDetector(
onTap: () {
onItemSelected(index);
},
child: _buildItem(item, selectedIndex == index),
),
);
}).toList(),
),
),
);
}