如何实现滚动时隐藏底部导航栏?(基于persistent_bottom_nav_bar)
问题解答
问题1:如何隐藏底部导航栏?
使用persistent_bottom_nav_bar包时,可通过控制hideNavigationBar参数切换导航栏的显示/隐藏状态,结合状态管理就能实现动态隐藏。
问题2:监听ListView滚动并动态隐藏底部导航栏
要实现子页面滚动联动父页面导航栏隐藏,需通过滚动控制器监听+跨页面状态传递实现,具体步骤如下:
步骤1:改造bottom_nav_bar.dart,添加状态控制
将原代码改为StatefulWidget,新增状态变量控制导航栏显示,并提供回调方法供子页面触发状态更新:
import 'package:flutter/material.dart'; import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart'; import 'package:sizer/sizer.dart'; import 'connection_view.dart'; class BottomNavBar extends StatefulWidget { const BottomNavBar({super.key}); @override State<BottomNavBar> createState() => _BottomNavBarState(); } class _BottomNavBarState extends State<BottomNavBar> { bool _isNavBarVisible = true; // 供子页面调用,更新导航栏显示状态 void updateNavBarVisibility(bool visible) { setState(() { _isNavBarVisible = visible; }); } @override Widget build(BuildContext context) { return Sizer(builder: ((context, orientation, deviceType) { return Scaffold( body: PersistentTabView( context, screens: [ // 将状态更新方法传递给子页面 ClientConnection(updateNavBar: updateNavBarVisibility), const ClientDiscover(), const ClientDiscover(), const ClientDiscover(), ], items: _navBarsItems(), navBarStyle: NavBarStyle.style1, bottomScreenMargin: 0, navBarHeight: 60, padding: const NavBarPadding.all(5), margin: const EdgeInsets.only( bottom: 15, left: 20, right: 20, ), decoration: const NavBarDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(30), topRight: Radius.circular(30), ), boxShadow: [ BoxShadow( color: Colors.grey, blurRadius: 5, offset: Offset(2, 2), ) ], ), // 核心:控制导航栏显示隐藏 hideNavigationBar: !_isNavBarVisible, // 添加过渡动画提升体验 navBarCurve: Curves.easeInOut, ), ); })); } List<PersistentBottomNavBarItem> _navBarsItems() { return [ PersistentBottomNavBarItem( icon: SvgPicture.asset( 'assets/active-connection-icon.svg', width: 5.w, ), title: ("CONNECTIONS"), inactiveIcon: SvgPicture.asset( 'assets/inactive-connection-icon.svg', width: 5.w, ), ), PersistentBottomNavBarItem( icon: SvgPicture.asset( 'assets/active-discover-icon.svg', width: 5.w, ), title: ("DISCOVER"), inactiveIcon: SvgPicture.asset( 'assets/inactive-discover-icon.svg', width: 5.w, ), ), PersistentBottomNavBarItem( icon: SvgPicture.asset( 'assets/active-profile-icon.svg', width: 5.w, ), title: ("PROFILE"), inactiveIcon: SvgPicture.asset( 'assets/inactive-profile-icon.svg', width: 5.w, ), ), PersistentBottomNavBarItem( icon: SvgPicture.asset( 'assets/active-notification-icon.svg', width: 5.w, ), title: ("NOTIFICATIONS"), inactiveIcon: SvgPicture.asset( 'assets/inactive-notification-icon.svg', width: 5.w, ), ), ]; } }
步骤2:改造connection_view.dart,添加滚动监听
在子页面中通过ScrollController监听滚动方向,根据偏移量判断是否触发导航栏隐藏:
import 'package:flutter/material.dart'; import 'package:sizer/sizer.dart'; // 定义回调类型,用于传递状态更新 typedef UpdateNavBarCallback = void Function(bool isVisible); class ClientConnection extends StatefulWidget { final UpdateNavBarCallback updateNavBar; const ClientConnection({super.key, required this.updateNavBar}); @override State<ClientConnection> createState() => _ClientConnectionState(); } class _ClientConnectionState extends State<ClientConnection> { late ScrollController _scrollController; // 记录上一次滚动位置,用于判断滚动方向 double _lastScrollOffset = 0; @override void initState() { super.initState(); _scrollController = ScrollController(); // 绑定滚动监听 _scrollController.addListener(_onScroll); } void _onScroll() { final currentOffset = _scrollController.offset; // 向下滚动(偏移量大于上次)且超过阈值时隐藏导航栏 if (currentOffset > _lastScrollOffset && currentOffset > 10) { widget.updateNavBar(false); } // 向上滚动(偏移量小于上次)且超过阈值时显示导航栏 else if (currentOffset < _lastScrollOffset - 10) { widget.updateNavBar(true); } // 更新上次滚动位置 _lastScrollOffset = currentOffset; } @override void dispose() { // 销毁控制器,避免内存泄漏 _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Sizer(builder: ((context, orientation, deviceType) { return Scaffold( appBar: AppBar( backgroundColor: Colors.white, elevation: 0, toolbarHeight: 10.h, title: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'Connections', style: TextStyle(color: Colors.black), ), SizedBox(width: 2.w), Container( width: 10.w, height: 6.h, decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: Colors.blue, ), ), ], ), ), body: ListView.builder( controller: _scrollController, physics: const ClampingScrollPhysics(), itemBuilder: (_, i) => ListTile(title: Text('Item $i')), itemCount: 20, ), ); })); } }
关键说明
- 跨页面状态传递:通过回调函数将子页面的滚动状态传递给父页面,实现联动控制。
- 滚动方向判断:对比当前与上次滚动偏移量,添加阈值(10)避免微小滚动导致导航栏频繁切换。
- 资源管理:在子页面销毁时释放
ScrollController,防止内存泄漏。
内容的提问来源于stack exchange,提问作者wuuyungwuu
相关产品推荐
相关产品推荐

