Flutter中BottomNavigationBar结合BlocConsumer不重建问题求助
问题原因分析
你的问题核心出在CustomBottomNavBar的BlocConsumer使用逻辑上:
- 在
build方法内定义的int selectedIndex = 0是局部变量,每次BlocConsumer因状态变化触发builder重建时,这个变量都会被重新初始化为0。 - 虽然listener回调里会把
selectedIndex更新为state的值,但listener执行在builder重建之前,等builder执行时,又会重新将selectedIndex设为0,导致BottomNavigationBar的currentIndex始终是初始值0,无法同步选中状态。
另外,RootPage里手动维护的selectedIndex变量属于冗余状态,直接使用Bloc中的状态即可。
修复代码
修改CustomBottomNavBar.dart
移除局部变量和无用的listener,直接在builder中使用state的selectedIndex:
import 'package:cook_meet_repeat/application/root/root_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class CustomBottomNavBar extends StatelessWidget { const CustomBottomNavBar({super.key}); @override Widget build(BuildContext context) { final themeData = Theme.of(context); return BlocBuilder<RootBloc, RootBottomNavigationState>( builder: (context, state) { return BottomNavigationBar( type: BottomNavigationBarType.fixed, backgroundColor: themeData.primaryColor, unselectedFontSize: 14, items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.set_meal_rounded), label: 'Events', ), BottomNavigationBarItem( icon: Icon(Icons.groups), label: 'Community', ), BottomNavigationBarItem( icon: Icon(Icons.add_circle), label: 'Host', ), BottomNavigationBarItem( icon: Icon(Icons.message_rounded), label: 'Messages', ), BottomNavigationBarItem( icon: Icon(Icons.person_4_rounded), label: 'Profile', ), ], currentIndex: state.selectedIndex, selectedItemColor: Colors.amber[800], selectedFontSize: 14, onTap: (index) { print("tapped on: $index"); BlocProvider.of<RootBloc>(context).add( RootBottomNavigationPressed(selectedIndex: index)); } ); }); } }
修改RootPage.dart
移除手动维护的selectedIndex变量,直接使用Bloc状态的索引:
import 'package:auto_route/auto_route.dart'; import 'package:cook_meet_repeat/application/auth/auth/auth_bloc.dart'; import 'package:cook_meet_repeat/application/root/root_bloc.dart'; import 'package:cook_meet_repeat/presentation/custom_bottom_nav_bar.dart'; import 'package:cook_meet_repeat/presentation/root/events/events_page.dart'; import 'package:cook_meet_repeat/presentation/root/host_events/host_events.dart'; import 'package:cook_meet_repeat/presentation/routes/router.gr.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../constants/icons.dart'; @RoutePage() class RootPage extends StatefulWidget { const RootPage({super.key}); @override State<RootPage> createState() => _RootPageState(); } class _RootPageState extends State<RootPage> { final pages = [EventsPage(), HostEventsPage(), Placeholder(), Placeholder(), Placeholder()]; @override Widget build(BuildContext context) { return MultiBlocListener( listeners: [ BlocListener<AuthBloc, AuthState>(listener: (context, state) { if (state is AuthStateAuthenticated) { AutoRouter.of(context).push(const SignupRoute()); } }), ], child: BlocBuilder<RootBloc, RootBottomNavigationState>( builder: (context, state) { return Scaffold( body: pages[state.selectedIndex], bottomNavigationBar: const CustomBottomNavBar()); }, ), ); } }
额外说明
- 当只需要根据状态更新UI时,使用
BlocBuilder即可,BlocConsumer仅在需要监听状态变化执行非UI操作(如跳转、弹框)时才需要。 - 状态管理遵循单一数据源原则,尽量直接使用Bloc中的状态,避免在Widget层维护重复状态,减少状态不一致的风险。
内容的提问来源于stack exchange,提问作者Cxyda
相关产品推荐
相关产品推荐

