Flutter:如何实现Persistent_bottom_nav_bar_v2购物车数量自动更新
问题背景
在Flutter应用中使用Persistent Bottom Navigation Bar Version 2包,购物车支持商品增减操作,但底部导航栏的购物车数量需要点击导航栏才会更新。期望调用购物车API获取数据后,底部导航栏的商品数量能自动刷新,无需手动点击。
核心问题分析
当前代码中,底部导航栏的_navbarItems()依赖cartManager.cartCount渲染,但没有监听cartCount的变化,只有点击导航栏时通过setState触发重建,因此无法自动响应购物车数据更新。
解决步骤
- 监听购物车状态变化:利用Bloc或状态管理类的监听机制,在购物车数据更新时触发UI重建。
- 开启导航栏状态管理:将
PersistentTabView的stateManagement设为true,让导航栏能响应外部状态变化自动刷新。 - 同步最新购物车数据:确保导航栏渲染时能获取到最新的购物车数量。
修改后的完整代码
import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; // 导入其他必要依赖包 class BottomNavBar extends StatefulWidget { bool? cameFromSplash; BottomNavBar({super.key, this.cameFromSplash = false}); @override State<BottomNavBar> createState() => _BottomNavBarState(); } class _BottomNavBarState extends State<BottomNavBar> { late CartBloc _cartBloc; CartManager cartManager = CartManager(); PersistentTabController? _controller; @override void initState() { super.initState(); _cartBloc = context.read<CartBloc>(); _controller = PersistentTabController(initialIndex: 0); // 监听CartBloc状态变化,购物车数据更新时触发UI重建 _cartBloc.stream.listen((state) { if (state is CartLoadedState) { // 根据你的Bloc实际状态类型调整 setState(() { // 同步最新购物车数量到cartManager cartManager.cartCount = state.cartItems.length; }); } }); initConnectivity(); } List<Widget> _buildScreens() { return [ Screen1(), Screen2(), Screen3(), CartScreen(), Screen5(), Screen6(), ]; } List<PersistentBottomNavBarItem> _navbarItems() { return [ // 其他导航项保持不变 PersistentBottomNavBarItem( icon: cartManager.cartCount == 0 ? SvgPicture.asset( AppImages.pic1, height: 5.h, color: AppColors.kgrey, ) : badges.Badge( badgeContent: Text( cartManager.cartCount.toString(), style: sans12light.copyWith(color: AppColors.kblack), ), child: SvgPicture.asset( AppImages.pic1, height: 5.h, color: _controller!.index == 3 ? AppColors.kred : AppColors.kgrey, ), ), activeColorPrimary: AppColors.kred, inactiveColorPrimary: Colors.grey, ), // 剩余导航项保持不变 ]; } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.kwhite, body: PersistentTabView( context, screens: _buildScreens(), popAllScreensOnTapOfSelectedTab: true, popAllScreensOnTapAnyTabs: true, items: _navbarItems(), controller: _controller, stateManagement: true, // 开启导航栏状态管理 navBarStyle: NavBarStyle.style8, onItemSelected: (index) { setState(() { _controller!.index = index; }); }, ), ); } } // CustomNavBarWidget代码保持不变 class CustomNavBarWidget extends StatefulWidget { final int? selectedIndex; final List<PersistentBottomNavBarItem>? items; final ValueChanged<int>? onItemSelected; const CustomNavBarWidget({ super.key, this.selectedIndex, required this.items, this.onItemSelected, }); @override State<CustomNavBarWidget> createState() => _CustomNavBarWidgetState(); } class _CustomNavBarWidgetState extends State<CustomNavBarWidget> { 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.activeColorSecondary ?? item.activeColorPrimary) : item.inactiveColorPrimary ?? item.activeColorPrimary, ), child: isSelected ? item.icon : item.inactiveIcon ?? 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 ?? item.activeColorPrimary) : item.inactiveColorPrimary, fontWeight: FontWeight.w400, fontFamily: 'Calibri', fontSize: 12.0, ), ), ), ), ), ], ), ); } @override Widget build(BuildContext context) { return Container( color: Colors.white, child: SizedBox( width: double.infinity, height: kBottomNavigationBarHeight, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: widget.items!.map((item) { int index = widget.items!.indexOf(item); return Expanded( child: InkWell( onTap: () { widget.onItemSelected!(index); }, child: _buildItem(item, widget.selectedIndex == index), ), ); }).toList(), ), ), ); } }
关键修改说明
- Bloc状态监听:在
initState中添加_cartBloc.stream.listen,当购物车数据加载完成时,调用setState同步最新数量并重建导航栏。 - stateManagement配置:将
PersistentTabView的stateManagement设为true,确保导航栏能感知外部状态变化并自动刷新。 - 备选方案(ChangeNotifier):如果使用
ChangeNotifier管理购物车状态,可替换为以下监听代码:@override void initState() { super.initState(); cartManager.addListener(() { setState(() {}); }); }
内容的提问来源于stack exchange,提问作者Mubashir Nawaz
相关产品推荐
相关产品推荐

