Flutter底部导航栏持久化插件persistent_bottom_nav_bar_plus的使用

发布于 1周前 作者 itying888 来自 Flutter

Flutter底部导航栏持久化插件persistent_bottom_nav_bar_plus的使用

整体介绍

persistent_bottom_nav_bar_plus 是一个用于Flutter的底部导航栏插件,它提供了高度可定制的底部导航栏功能。 该插件支持在iOS和Android设备上使用,并且可以处理硬件/软件的Android返回按钮。

安装依赖

首先,在你的Flutter项目中添加以下依赖:

dependencies:
  persistent_bottom_nav_bar_plus: any

导入包

在你的代码中导入 persistent_bottom_nav_bar_plus 包:

import 'package:persistent_bottom_nav_bar_plus/persistent_tab_view.dart';

声明控制器

声明 PersistentTabController 作为底部导航栏的控制器:

PersistentTabController _controller;

_controller = PersistentTabController(initialIndex: 0);

主要组件

主要组件是 PersistentTabView,这个组件包含了Scaffold(基于CupertinoTabScaffold),所以不需要单独声明Scaffold。以下是一个示例代码:

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, // 默认白色背景
      handleAndroidBackButtonPress: true, // 默认为true
      resizeToAvoidBottomInset: true, // 默认为true
      stateManagement: true, // 默认为true
      hideNavigationBarWhenKeyboardShows: true, // 推荐设置'resize to avoid bottom inset'为true时使用此参数。默认为true
      decoration: NavBarDecoration(
        borderRadius: BorderRadius.circular(10.0),
        colorBehindNavBar: Colors.white,
      ),
      popAllScreensOnTapOfSelectedTab: true,
      popActionScreens: PopActionScreensType.all,
      itemAnimationProperties: ItemAnimationProperties( // 导航栏项目的动画属性。
        duration: Duration(milliseconds: 200),
        curve: Curves.ease,
      ),
      screenTransitionAnimation: ScreenTransitionAnimation( // 屏幕切换动画
        animateTabTransition: true,
        curve: Curves.ease,
        duration: Duration(milliseconds: 200),
      ),
      navBarStyle: NavBarStyle.style1, // 选择导航栏样式
    );
  }
}

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,
    ),
  ];
}

跳转屏幕

你可以使用以下函数来控制底部导航栏的可见性:

  • pushNewScreen(context, screen, withNavBar: true):在Android上不显示底部导航栏,在iOS上显示底部导航栏。
  • pushNewScreenWithRouteSettings(context, settings, screen, withNavBar: true):与上面类似,但带有路由设置。
PersistentNavBarNavigator.pushNewScreen(
  context,
  screen: MainScreen(),
  withNavBar: true, // 可选值,默认为true
  pageTransitionAnimation: PageTransitionAnimation.cupertino,
);

PersistentNavBarNavigator.pushNewScreenWithRouteSettings(
  context,
  settings: RouteSettings(name: MainScreen.routeName),
  screen: MainScreen(),
  withNavBar: true,
  pageTransitionAnimation: PageTransitionAnimation.cupertino,
);

部分有用的提示

  • 弹出到导航图中的任何屏幕:

    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,
    );
    

自定义导航栏样式

如果你想要自定义导航栏样式,请按照以下步骤操作:

  1. 定义自定义的导航栏项。请注意,你需要自己处理 onSelectedItemselectedIndex 函数以保持完整功能。你也可以定义自己的导航栏项模型而不是提供的 PersistentBottomNavBarItem。以下是一个示例代码:
class CustomNavBarWidget extends StatelessWidget {
  final int selectedIndex;
  final List<PersistentBottomNavBarItem> items; // 注意:你可以在这里定义自己的模型代替 `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: 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(),
        ),
      ),
    );
  }
}
  1. 在主 PersistentTabView 组件中,将 navBarStyle 属性设置为 NavBarStyle.custom 并传递自定义的 widget 到 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, // 这是在自定义样式的情况下必需的!传递导航栏项的数量。
      screens: _buildScreens(),
      confineInSafeArea: true,
      handleAndroidBackButtonPress: true,
      onItemSelected: (int) {
        setState(() {}); // 这是为了更新导航栏如果Android返回按钮被按下
      },
      customWidget: CustomNavBarWidget(
        items: _navBarsItems(),
        selectedIndex: _controller.index,
        onItemSelected: (index) {
          setState(() {
            _controller.index = index; // 注意:这是至关重要的的!不要错过它!
          });
        },
      ),
    );
  }
}
  1. 完成后,确保一些其他属性如 iconSizeitems 不需要在此处指定,因此可以忽略这些属性。为了控制屏幕底部的填充,使用 bottomScreenPadding。如果给定的 bottomScreenPadding 量而自定义 widget 的的高度不足或反之,则可能会出现布局问题。

示例项目

对于更好的理解,请参考官方GitHub仓库中的示例项目:

https://github.com/SujitChanda/persistent_bottom_nav_bar_plus/tree/master/example


更多关于Flutter底部导航栏持久化插件persistent_bottom_nav_bar_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter底部导航栏持久化插件persistent_bottom_nav_bar_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 persistent_bottom_nav_bar_plus 插件来在 Flutter 应用中实现持久化底部导航栏的示例代码。这个插件允许你创建一个持久的底部导航栏,即使在不同的页面之间切换时,导航栏的状态也能保持不变。

首先,确保你已经在 pubspec.yaml 文件中添加了 persistent_bottom_nav_bar_plus 依赖:

dependencies:
  flutter:
    sdk: flutter
  persistent_bottom_nav_bar_plus: ^x.y.z  # 请替换为最新版本号

然后,运行 flutter pub get 来安装依赖。

接下来,是主应用代码的实现。这里是一个完整的示例,展示了如何使用 persistent_bottom_nav_bar_plus 插件:

import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar_plus/persistent-theme.dart';
import 'package:persistent_bottom_nav_bar_plus/persistent_bottom_nav_bar.dart';

void main() {
  runApp(MyApp());
}

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

class PersistentBottomNavBarDemo extends StatefulWidget {
  @override
  _PersistentBottomNavBarDemoState createState() => _PersistentBottomNavBarDemoState();
}

class _PersistentBottomNavBarDemoState extends State<PersistentBottomNavBarDemo> {
  final List<PersistentBottomNavBarItem> _navItems = [
    PersistentBottomNavBarItem(
      icon: Icon(Icons.home),
      title: ("Home"),
      routeAndNavigatorFunction: (context) {
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => HomeScreen()),
        );
      },
    ),
    PersistentBottomNavBarItem(
      icon: Icon(Icons.search),
      title: ("Search"),
      routeAndNavigatorFunction: (context) {
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => SearchScreen()),
        );
      },
    ),
    PersistentBottomNavBarItem(
      icon: Icon(Icons.library_books),
      title: ("Library"),
      routeAndNavigatorFunction: (context) {
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => LibraryScreen()),
        );
      },
    ),
    PersistentBottomNavBarItem(
      icon: Icon(Icons.profile),
      title: ("Profile"),
      routeAndNavigatorFunction: (context) {
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => ProfileScreen()),
        );
      },
    ),
  ];

  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    return PersistentTabView(
      context,
      screens: [
        HomeScreen(),
        SearchScreen(),
        LibraryScreen(),
        ProfileScreen(),
      ],
      items: _navItems,
      initialIndex: _selectedIndex,
      confineInSafeArea: true,
      backgroundColor: Colors.white,
      handleBackPressure: true,
      decoration: NavBarDecoration(
        borderRadius: BorderRadius.circular(10),
        colorBehindNavBar: Colors.white,
      ),
      popActionScreens: PopActionScreensType.all,
      itemAnimationProperties: ItemAnimationProperties(
        duration: Duration(milliseconds: 200),
        curve: Curves.ease,
      ),
      screenTransitionAnimation: ScreenTransitionAnimation(
        animateTabTransition: true,
        curve: Curves.ease,
        duration: Duration(milliseconds: 200),
      ),
      navBarStyle: NavBarStyle.style12,
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home Screen'),
      ),
      body: Center(
        child: Text('This is the Home Screen'),
      ),
    );
  }
}

class SearchScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Search Screen'),
      ),
      body: Center(
        child: Text('This is the Search Screen'),
      ),
    );
  }
}

class LibraryScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Library Screen'),
      ),
      body: Center(
        child: Text('This is the Library Screen'),
      ),
    );
  }
}

class ProfileScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Profile Screen'),
      ),
      body: Center(
        child: Text('This is the Profile Screen'),
      ),
    );
  }
}

在这个示例中,我们定义了一个 PersistentBottomNavBarDemo 类,它包含了四个导航项(Home, Search, Library, Profile)。每个导航项都有一个图标、标题和一个导航函数,用于在点击时导航到相应的页面。PersistentTabView 组件用于显示底部导航栏和相应的页面。

这个示例展示了如何使用 persistent_bottom_nav_bar_plus 插件创建一个持久的底部导航栏,并确保导航栏的状态在切换页面时保持不变。你可以根据需要进一步自定义和扩展这个示例。

回到顶部