I am stuck at a problem where I am using GoRouter package for routing and for bottom navigation bar I am using a StatefullShellBranch.
Current behaviour is I have 4 navigation branches, and all are working well. Whenever screen I am when back is pressed it closes the app, whether I am on the home or profile or the chat or any where on the bottom navigation bar .
Expected behaviour
What I want is that if the user is on the bottom navigation bar on the home index I want it the user press back or use gestures it should show a popUp like whether to close the app or if the user is another branch or index on the bottom navigation bar when is press back it should go to the home index or the home branch
Can anyone help me ..? With this
I have use the Pop Scope but it is not working..
I have use the Pop Scope and the onExit property of the goRoute but it is not working.
I would like to add that when using the StatefullShellBranch when I use the onExit property and creating the method as onExitPopUp, it works when I press back but when i navigate on the navigation branch it ask the same would you like to close the app I think when I changed the branch in the bottom navigation bar it act like closing the app
This is the route code
this is the bottom nav bar code
enum UserType { influencer, brand }
class MyCustomBottomNavigationBar extends StatefulWidget {
MyCustomBottomNavigationBar({
required this.navigationShell,
required this.bottomNavNavigationHandlerCubit,
required this.userType,
super.key,
});
final StatefulNavigationShell navigationShell;
final BottomNameNavigationHandlerCubit bottomNavNavigationHandlerCubit;
final UserType userType;
static Widget create({
required StatefulNavigationShell navigationShell,
required UserType userType,
}) {
return BlocProvider<BottomNameNavigationHandlerCubit>(
create: (context) => BottomNameNavigationHandlerCubit(),
child: Consumer<BottomNameNavigationHandlerCubit>(
builder: (_, BottomNameNavigationHandlerCubit cubit, __) =>
MyCustomBottomNavigationBar(
navigationShell: navigationShell,
bottomNavNavigationHandlerCubit: cubit,
userType: userType,
),
),
);
}
@override
MyCustomBottomNavigationBarState createState() =>
MyCustomBottomNavigationBarState();
}
class MyCustomBottomNavigationBarState
extends State<MyCustomBottomNavigationBar> {
void _goBranch(int index) {
widget.navigationShell.goBranch(
index,
initialLocation: index == widget.navigationShell.currentIndex,
);
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
List<IconData> icons = [];
List<String> labels = [];
// Update icons and labels based on user type
if (widget.userType == UserType.influencer) {
icons = [
Icons.home_rounded,
Icons.play_arrow_rounded,
Icons.message_rounded,
Icons.person_rounded,
];
labels = ['Home', 'Reels', 'Messages', 'Profile'];
} else if (widget.userType == UserType.brand) {
icons = [
Icons.home_rounded,
Icons.contacts_rounded,
Icons.message_rounded,
Icons.person_rounded,
];
labels = ['Home', 'Phonebook', 'Messages', 'Profile'];
}
return PopScope(
canPop: true,
onPopInvoked: (value){
debugPrint('onPOPInvoke on botton-------------$value');
if(!value){
context.goNamed(RouteStrings.homeScreen);
}
},
child: Scaffold(
backgroundColor: AppStyle.colors.background,
extendBodyBehindAppBar: true,
body: SafeArea(
child: SizedBox.expand(
child: widget.navigationShell,
),
),
bottomNavigationBar: Container(
height: size.width * .155,
child: BlocBuilder<BottomNameNavigationHandlerCubit, int>(
builder: (context, state) {
return ListView.builder(
itemCount: 4,
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: size.width * .024),
itemBuilder: (context, index) => InkWell(
onTap: () {
debugPrint('tapped index : $index');
context.read<BottomNameNavigationHandlerCubit>().updateValue(
value: index,
);
if (widget.userType == UserType.brand) {
if (index == 1) {
_goBranch(4);
} else {
_goBranch(index);
}
} else {
_goBranch(index);
}
},
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(height: size.width * .014),
Icon(icons[index],
size: size.width * .076, color: Colors.grey.shade500),
AnimatedContainer(
duration: const Duration(milliseconds: 1500),
curve: Curves.fastLinearToSlowEaseIn,
margin: EdgeInsets.only(
top: index == state ? 0 : size.width * .029,
right: size.width * .0422,
left: size.width * .0422,
),
width: size.width * .153,
height: index == state ? size.width * .014 : 0,
decoration: BoxDecoration(
color: Colors.grey.shade500,
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
),
],
),
),
);
},
),
),
),
);
}
}
this is the profile code i.e
class ProfileScreen extends StatefulWidget {
const ProfileScreen({super.key});
@override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
@override
void dispose() {
if(context.mounted){
context.pushNamed(RouteStrings.homeScreen);
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return PopScope(
// canPop: showExitConfirmation(context),
canPop: false,
onPopInvoked: (value){
debugPrint('onPOPInvoke-------------$value');
if(!value){
showExitConfirmation(context);
context.goNamed(RouteStrings.homeScreen);
}
},
child: const Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Text('Profile Screen'),
),
),
);
}
}
if any things require let me know
Your problem is not really related to GoRouter or how you use
StatefullShellBranch, but to how Android an iOS handle pop/back gestures.You shall:
android:enableOnBackInvokedCallback="true"as it is indicate on the package documentacion for it to work)In your case solution could be to have a widget class
ShelledPagewhich is then extended by you routes: