持久底部导航栏
Flutter 的持久/静态底部导航栏。
注意:从 2.0.0 版本之前迁移的用户应查看最新的 Readme 和说明,因为 2.0.0 更新引入了许多重大更改。
样式
| 样式15 | 样式16 |
|---|---|
![]() |
![]() |
| 样式1 | 样式9 |
|---|---|
![]() |
![]() |
| 样式7 | 样式10 |
|---|---|
![]() |
![]() |
| 样式12 | 样式13 |
|---|---|
![]() |
![]() |
| 样式3 | 样式6 |
|---|---|
![]() |
![]() |
| Neumorphic | 仿拟风格,无副标题 |
|---|---|
![]() |
![]() |
注意:这些不包含所有样式变体。
功能
- 高度可定制的“持久”底部导航栏。
- 能够推入新屏幕,带或不带底部导航栏。
- 20种底部导航栏样式。
- 包含用于推入屏幕(带或不带底部导航栏)的函数,即 `pushNewScreen()` 和 `pushNewScreenWithRouteSettings()`。
- 基于 Flutter 的 Cupertino (iOS) 底部导航栏。
- 对于特定标签页,可以是“半透明”的。
- 自定义导航栏样式。点击 此处 了解更多信息。
- 处理 Android 硬件/软件返回按钮。
入门
在您的 Flutter 项目中添加依赖项
dependencies:
persistent_bottom_nav_bar: any
导入包
import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart';
持久底部导航栏使用 `PersistentTabController` 作为其控制器。以下是声明它的方法:
PersistentTabController _controller;
_controller = PersistentTabController(initialIndex: 0);
然后声明的主要小部件是 `PersistentTabView`。注意:此小部件包含 SCAFFOLD (基于 `CupertinoTabScaffold`),因此无需声明它。以下是一个用于演示的示例:
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return PersistentTabView(
context,
controller: _controller,
screens: _buildScreens(),
items: _navBarsItems(),
confineInSafeArea: true,
backgroundColor: Colors.white, // Default is Colors.white.
handleAndroidBackButtonPress: true, // Default is true.
resizeToAvoidBottomInset: true, // This needs to be true if you want to move up the screen when keyboard appears. Default is true.
stateManagement: true, // Default is true.
hideNavigationBarWhenKeyboardShows: true, // Recommended to set 'resizeToAvoidBottomInset' as true while using this argument. Default is true.
decoration: NavBarDecoration(
borderRadius: BorderRadius.circular(10.0),
colorBehindNavBar: Colors.white,
),
popAllScreensOnTapOfSelectedTab: true,
popActionScreens: PopActionScreensType.all,
itemAnimationProperties: ItemAnimationProperties( // Navigation Bar's items animation properties.
duration: Duration(milliseconds: 200),
curve: Curves.ease,
),
screenTransitionAnimation: ScreenTransitionAnimation( // Screen transition animation on change of selected tab.
animateTabTransition: true,
curve: Curves.ease,
duration: Duration(milliseconds: 200),
),
navBarStyle: NavBarStyle.style1, // Choose the nav bar style with this property.
);
}
}
List<Widget> _buildScreens() {
return [
MainScreen(),
SettingsScreen()
];
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: Icon(CupertinoIcons.home),
title: ("Home"),
activeColorPrimary: CupertinoColors.activeBlue,
inactiveColorPrimary: CupertinoColors.systemGrey,
),
PersistentBottomNavBarItem(
icon: Icon(CupertinoIcons.settings),
title: ("Settings"),
activeColorPrimary: CupertinoColors.activeBlue,
inactiveColorPrimary: CupertinoColors.systemGrey,
),
];
}
导航器函数
注意:您仍然可以使用常规的 Navigator 函数,例如 ‘pushNamed’,但请务必检查 `PersistentBottomNavBarItem` 中的 `routeAndNavigatorSettings` 参数以获取路由设置和其他一些与导航器相关的属性。 要推入新屏幕,请使用以下函数来控制特定屏幕上底部导航栏的“可见性”。您可以使用自己的逻辑来实现“特定平台”的行为。一种解决方案是使用 `withNavBar` 属性并根据平台进行切换。
在“特定平台”行为中,当推入新屏幕时,在 Android 上它将不带底部导航栏推入屏幕,但在 iOS 上它将保留底部导航栏。这是每个平台指定的默认行为。
PersistentNavBarNavigator.pushNewScreen(
context,
screen: MainScreen(),
withNavBar: true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation: PageTransitionAnimation.cupertino,
);
PersistentNavBarNavigator.pushNewScreenWithRouteSettings(
context,
settings: RouteSettings(name: MainScreen.routeName),
screen: MainScreen(),
withNavBar: true,
pageTransitionAnimation: PageTransitionAnimation.cupertino,
);
如果您要推入新的“模态”屏幕,请使用以下函数:
PersistentNavBarNavigator.pushDynamicScreen(
context,
screen: HomeModalScreen(),
withNavBar: true,
);
一些有用的提示
-
弹出到给定标签页导航图中的任何屏幕
Navigator.of(context).popUntil((route) { return route.settings.name == "ScreenToPopBackTo"; });
-
弹出到给定标签页导航图中的第一个屏幕
Navigator.of(context).popUntil(ModalRoute.withName("/"));
Navigator.of(context).pushAndRemoveUntil( CupertinoPageRoute( builder: (BuildContext context) { return FirstScreen(); }, ), (_) => false, );
-
要将底部工作表推到导航栏之上,请使用 `showModalBottomScreen` 并将其属性 `useRootNavigator` 设置为 true。请参阅示例项目以获得说明。
自定义导航栏样式
如果您想要自己的导航栏样式,请遵循以下步骤:
-
声明您的自定义小部件。请牢记,您需要自己处理 `onSelectedItem` 函数和 `selectedIndex` 整数以保持全部功能。另请注意,您可以定义自己的导航栏项模型,而不是使用提供的 `PersistentBottomNavBarItem`。请参阅下面的示例以更好地理解。
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.activeColorSecondary == null ? item.activeColorPrimary : item.activeColorSecondary) : item.inactiveColorPrimary == null ? item.activeColorPrimary : item.inactiveColorPrimary), 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.activeColorSecondary == null ? item.activeColorPrimary : item.activeColorSecondary) : item.inactiveColorPrimary, fontWeight: FontWeight.w400, fontSize: 12.0), )), ), ) ], ), ); } @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) { int index = items.indexOf(item); return Flexible( child: GestureDetector( onTap: () { this.onItemSelected(index); }, child: _buildItem( item, selectedIndex == index), ), ); }).toList(), ), ), ); } }
-
在主 `PersistentTabView` 小部件中,将 `navBarStyle` 属性设置为 `NavBarStyle.custom`,并将您刚刚创建的自定义小部件通过 `customWidget` 属性传递进来,如下所示:
class MyApp extends StatelessWidget { const MyApp({Key key}) : super(key: key); @override Widget build(BuildContext context) { return PersistentTabView.custom( context, 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: (index) { setState(() { _controller.index = index; // NOTE: THIS IS CRITICAL!! Don't miss it! }); }, ), ); } }
注意:在 `customWidget` 的 `onSelected` 函数中,不要忘记更改控制器的索引。 -
完成!如我们所见,其他一些属性,如 `iconSize`、`items` 等在这里不是必需的,因此您可以跳过这些属性。要控制屏幕的“底部填充”,请使用 `bottomScreenPadding`。如果您设置了过多的 `bottomScreenPadding` 但自定义小部件中的高度较低,或者反之亦然,可能会出现布局问题。
为了更好地理解,请参阅官方 git 仓库中的 示例项目。












