Hey there I’m pretty new to flutter. I’m trying to get my BottomNavigationBar
running. I’m using the bloc package for state changes, sending out an event when tapping on a BottomNavigationBar
. I have 2 BlocConsumers… 1 in my root page to swap out the page and 1 BlocConsumer
in my CustomBottomNavBar
widget. When testing they separately (so when only having 1 BlocConsumer listening to my event) it works. Also when I have both BlocConsumers the listeners work, I see my custom message printed to the console, but the BottomNavigationBar
for some reason is not rebuilding. Any idea why that is? Thanks a lot for your help!
VideoLink to proof that the Bottom Bar does not rebuild:
root.dart:
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()];
var selectedIndex = 0;
@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: BlocConsumer<RootBloc, RootBottomNavigationState>(
listener: (context, state) {
selectedIndex = state.selectedIndex;
print("RootPage selectedIndex $selectedIndex");
}, builder: (context, state) {
return Scaffold(
body: pages[selectedIndex],
bottomNavigationBar: CustomBottomNavBar());
}),
);
}
}
custom_bottom_nav_bar.dart:
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);
int selectedIndex = 0;
return BlocConsumer<RootBloc, RootBottomNavigationState>(
listener: (context, state) {
selectedIndex = state.selectedIndex;
print("CustomBottomNavBar selectedIndex: $selectedIndex");
},
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: selectedIndex,
selectedItemColor: Colors.amber[800],
selectedFontSize: 14,
onTap: (index) {
print("tapped on: $index");
BlocProvider.of<RootBloc>(context).add(
RootBottomNavigationPressed(selectedIndex: index));
}
);
});
}
}
My Console Log which proofs that the listeners work
I/flutter (17333): tapped on: 2
I/flutter (17333): RootPage selectedIndex 2
I/flutter (17333): CustomBottomNavBar selectedIndex: 2
D/EGL_emulation(17333): app_time_stats: avg=11.14ms min=5.94ms max=45.80ms count=57
I/flutter (17333): tapped on: 3
I/flutter (17333): RootPage selectedIndex 3
I/flutter (17333): CustomBottomNavBar selectedIndex: 3
Tested the BlocConsumers seperately… they work separately
2
Answers
In
CustomBottomNavBar
class:Don’t define
selectedIndex = 0
inbuild
. It will be re assign to 0 when build get called. Just get selectedIndex fromstate
ofBlocConsumer builder(context, state)
.In your case
selectedIndex = state.selectedIndex
is unnecessary. Just useBlocBuilder
and you can removelistener
blockHope it can help you.
Just remnove this line:
You don’t need store this value in widget because you should react on it changes getting it from your state: