您可以在下面复制粘贴运行完整代码
您可以使用包https://pub.dev/packages/persistent_bottom_nav_bar
在工作演示中,您可以看到每个屏幕都有自己的路线,并且导航时图标处于活动状态
工作演示
完整代码
import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.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: MainMenu(),
initialRoute: '/',
);
}
}
class MainMenu extends StatefulWidget {
MainMenu({Key key}) : super(key: key);
@override
_MainMenuState createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample Project"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: RaisedButton(
child: Text("Custom widget example"),
onPressed: () => pushNewScreen(
context,
screen: CustomWidgetExample(
menuScreenContext: context,
),
),
),
),
SizedBox(height: 20.0),
Center(
child: RaisedButton(
child: Text("Built-in styles example"),
onPressed: () => pushNewScreen(
context,
screen: ProvidedStylesExample(
menuScreenContext: context,
),
),
),
),
],
),
);
}
}
// ----------------------------------------- Provided Style ----------------------------------------- //
class ProvidedStylesExample extends StatefulWidget {
final BuildContext menuScreenContext;
ProvidedStylesExample({Key key, this.menuScreenContext}) : super(key: key);
@override
_ProvidedStylesExampleState createState() => _ProvidedStylesExampleState();
}
class _ProvidedStylesExampleState extends State<ProvidedStylesExample> {
PersistentTabController _controller;
bool _hideNavBar;
@override
void initState() {
super.initState();
_controller = PersistentTabController(initialIndex: 0);
_hideNavBar = false;
}
List<Widget> _buildScreens() {
return [
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
];
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: Icon(Icons.home),
title: "Home",
activeColor: Colors.blue,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.search),
title: ("Search"),
activeColor: Colors.teal,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.add),
title: ("Add"),
activeColor: Colors.blueAccent,
inactiveColor: Colors.grey,
activeContentColor: Colors.white,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.message),
title: ("Messages"),
activeColor: Colors.deepOrange,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.settings),
title: ("Settings"),
activeColor: Colors.indigo,
inactiveColor: Colors.grey,
),
];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Navigation Bar Demo')),
drawer: Drawer(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('This is the Drawer'),
],
),
),
),
body: PersistentTabView(
controller: _controller,
screens: _buildScreens(),
items: _navBarsItems(),
confineInSafeArea: true,
backgroundColor: Colors.white,
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true,
stateManagement: true,
hideNavigationBarWhenKeyboardShows: true,
hideNavigationBar: _hideNavBar,
margin: EdgeInsets.all(10.0),
popActionScreens: PopActionScreensType.once,
bottomScreenMargin: 0.0,
// onWillPop: () async {
// await showDialog(
// context: context,
// useSafeArea: true,
// builder: (context) => Container(
// height: 50.0,
// width: 50.0,
// color: Colors.white,
// child: RaisedButton(
// child: Text("Close"),
// onPressed: () {
// Navigator.pop(context);
// },
// ),
// ),
// );
// return false;
// },
decoration: NavBarDecoration(
colorBehindNavBar: Colors.indigo,
borderRadius: BorderRadius.circular(20.0)),
popAllScreensOnTapOfSelectedTab: true,
itemAnimationProperties: ItemAnimationProperties(
duration: Duration(milliseconds: 400),
curve: Curves.ease,
),
screenTransitionAnimation: ScreenTransitionAnimation(
animateTabTransition: true,
curve: Curves.ease,
duration: Duration(milliseconds: 200),
),
navBarStyle:
NavBarStyle.style15, // Choose the nav bar style with this property
),
);
}
}
// ----------------------------------------- Custom Style ----------------------------------------- //
class CustomNavBarWidget extends StatelessWidget {
final int selectedIndex;
final List<PersistentBottomNavBarItem> items;
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: kBottomNavigationBarHeight,
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: kBottomNavigationBarHeight,
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(),
),
),
);
}
}
class CustomWidgetExample extends StatefulWidget {
final BuildContext menuScreenContext;
CustomWidgetExample({Key key, this.menuScreenContext}) : super(key: key);
@override
_CustomWidgetExampleState createState() => _CustomWidgetExampleState();
}
class _CustomWidgetExampleState extends State<CustomWidgetExample> {
PersistentTabController _controller;
bool _hideNavBar;
@override
void initState() {
super.initState();
_controller = PersistentTabController(initialIndex: 0);
_hideNavBar = false;
}
List<Widget> _buildScreens() {
return [
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
MainScreen(
menuScreenContext: widget.menuScreenContext,
hideStatus: _hideNavBar,
onScreenHideButtonPressed: () {
setState(() {
_hideNavBar = !_hideNavBar;
});
},
),
];
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: Icon(Icons.home),
title: "Home",
activeColor: Colors.blue,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.search),
title: ("Search"),
activeColor: Colors.teal,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.add),
title: ("Add"),
activeColor: Colors.deepOrange,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.settings),
title: ("Settings"),
activeColor: Colors.indigo,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.settings),
title: ("Settings"),
activeColor: Colors.indigo,
inactiveColor: Colors.grey,
),
];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Navigation Bar Demo')),
drawer: Drawer(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('This is the Drawer'),
],
),
),
),
body: PersistentTabView(
controller: _controller,
screens: _buildScreens(),
confineInSafeArea: true,
itemCount: 5,
backgroundColor: Colors.white,
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true,
stateManagement: true,
hideNavigationBarWhenKeyboardShows: true,
hideNavigationBar: _hideNavBar,
decoration: NavBarDecoration(
colorBehindNavBar: Colors.indigo,
borderRadius: BorderRadius.circular(20.0)),
popAllScreensOnTapOfSelectedTab: true,
itemAnimationProperties: ItemAnimationProperties(
duration: Duration(milliseconds: 400),
curve: Curves.ease,
),
screenTransitionAnimation: ScreenTransitionAnimation(
animateTabTransition: true,
curve: Curves.ease,
duration: Duration(milliseconds: 200),
),
customWidget: CustomNavBarWidget(
items: _navBarsItems(),
onItemSelected: (index) {
setState(() {
_controller.index = index; // THIS IS CRITICAL!! Don't miss it!
});
},
selectedIndex: _controller.index,
),
navBarStyle:
NavBarStyle.custom, // Choose the nav bar style with this property
),
);
}
}
class MainScreen extends StatelessWidget {
final BuildContext menuScreenContext;
final Function onScreenHideButtonPressed;
final bool hideStatus;
const MainScreen(
{Key key,
this.menuScreenContext,
this.onScreenHideButtonPressed,
this.hideStatus = false})
: super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Scaffold(
backgroundColor: Colors.indigo,
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 20.0),
child: TextField(
decoration: InputDecoration(hintText: "Test Text Field"),
),
),
Center(
child: RaisedButton(
color: Colors.blue,
onPressed: () {
pushNewScreenWithRouteSettings(context,
settings: RouteSettings(name: '/home'),
screen: MainScreen2(),
pageTransitionAnimation:
PageTransitionAnimation.scaleRotate);
},
child: Text(
"Go to Second Screen ->",
style: TextStyle(color: Colors.white),
),
),
),
Center(
child: RaisedButton(
color: Colors.deepOrange,
onPressed: () {
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
useRootNavigator: true,
builder: (context) => Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
color: Colors.blue,
child: Text(
"Exit",
style: TextStyle(color: Colors.white),
),
),
),
);
},
child: Text(
"Push bottom sheet on TOP of Nav Bar",
style: TextStyle(color: Colors.white),
),
),
),
Center(
child: RaisedButton(
color: Colors.deepOrange,
onPressed: () {
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
useRootNavigator: false,
builder: (context) => Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
color: Colors.blue,
child: Text(
"Exit",
style: TextStyle(color: Colors.white),
),
),
),
);
},
child: Text(
"Push bottom sheet BEHIND the Nav Bar",
style: TextStyle(color: Colors.white),
),
),
),
Center(
child: RaisedButton(
color: Colors.lime,
onPressed: () {
pushDynamicScreen(context,
screen: SampleModalScreen(), withNavBar: true);
},
child: Text(
"Push Dynamic/Modal Screen",
style: TextStyle(color: Colors.white),
),
),
),
Center(
child: RaisedButton(
color: Colors.purpleAccent,
onPressed: () {
this.onScreenHideButtonPressed();
},
child: Text(
this.hideStatus
? "Unhide Navigation Bar"
: "Hide Navigation Bar",
style: TextStyle(color: Colors.white),
),
),
),
Center(
child: RaisedButton(
color: Colors.red,
onPressed: () {
Navigator.of(this.menuScreenContext).pop();
},
child: Text(
"<- Main Menu",
style: TextStyle(color: Colors.white),
),
),
),
SizedBox(
height: 60.0,
),
],
),
),
),
);
}
}
class MainScreen2 extends StatelessWidget {
const MainScreen2({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.teal,
body: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
color: Colors.indigo,
onPressed: () {
pushNewScreen(context, screen: MainScreen3());
},
child: Text(
"Go to Third Screen",
style: TextStyle(color: Colors.white),
),
),
RaisedButton(
color: Colors.indigo,
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Go Back to First Screen",
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
);
}
}
class MainScreen3 extends StatelessWidget {
const MainScreen3({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.deepOrangeAccent,
body: Container(
child: Center(
child: RaisedButton(
color: Colors.blue,
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Go Back to Second Screen",
style: TextStyle(color: Colors.white),
),
),
),
),
);
}
}
class SampleModalScreen extends ModalRoute<void> {
SampleModalScreen();
@override
Duration get transitionDuration => Duration(milliseconds: 500);
@override
bool get opaque => false;
@override
bool get barrierDismissible => false;
@override
Color get barrierColor => Colors.black.withOpacity(0.5);
@override
String get barrierLabel => null;
@override
bool get maintainState => true;
@override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
// This makes sure that text and other content follows the material style
return Material(
type: MaterialType.transparency,
// make sure that the overlay content is not cut off
child: SafeArea(
child: _buildOverlayContent(context),
),
);
}
Widget _buildOverlayContent(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height * 0.3,
width: MediaQuery.of(context).size.width * 0.3,
margin: EdgeInsets.all(30.0),
padding: EdgeInsets.symmetric(horizontal: 30.0),
color: Colors.amber,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"This is a modal screen",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 26.0,
),
),
Center(
child: RaisedButton(
color: Colors.blue,
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Return",
style: TextStyle(color: Colors.white),
),
),
),
],
),
);
}
}