I just recently started studying Dart / Flutter and ran into a problem: the system back button on android does not return to the previous screen, instead it closes the application.
When I was looking at ways to create nested pages, I wrote the following code:
// settings_navigator.dart
class SettingsNavigator extends StatelessWidget {
const SettingsNavigator({super.key});
@override
Widget build(BuildContext context) {
return Navigator(
onGenerateRoute: (settings) {
switch (settings.name) {
case '/notifications':
return UnanimatedPageRoute(
builder: (context) => const NotificationsScreen(),
);
default:
return MaterialPageRoute(
builder: (context) => const SettingsScreen(),
);
}
},
);
}
}
This approach was due to the fact that I wanted to place the bottom menu on all screens, however, with the standard approach, it was overlapped by a nested page
In my code, "default" is responsible for the parent page, and "case ‘/notifications’" for the nested one.
On the "notification" subpage, I have an appbar:
return AppBar(
titleSpacing: 0,
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Text(title),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
);
As you can see, it is used here Navigator.pop(context);
I tried using PopScope, but it didn’t lead to anything:
class SettingsNavigator extends StatelessWidget {
const SettingsNavigator({super.key});
@override
Widget build(BuildContext context) {
return PopScope(
onPopInvokedWithResult: (didPop, result) {
Navigator.pop(context);
},
child: Navigator(
onGenerateRoute: (settings) {
switch (settings.name) {
case '/notifications':
return UnanimatedPageRoute(
builder: (context) => const NotificationsScreen(),
);
default:
return MaterialPageRoute(
builder: (context) => const SettingsScreen(),
);
}
},
),
);
}
}
I assume this behavior is related to my route architecture, but I have not found meaningful information on the Internet with step-by-step creation of applications with nested pages.
I will also give the main.dart using the recommendation from the user "Handelika"
main.dart
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Schedule App',
theme: AppConfig.themeData(),
localizationsDelegates: AppConfig.localizationsDelegates,
supportedLocales: AppConfig.getSupportedLocales(),
locale: AppConfig.getDefaultLocale(),
home: const MainScreen(),
routes: routes(),
onGenerateRoute: generateRoute,
);
}
}
class MainScreen extends StatefulWidget {
const MainScreen({super.key});
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int _selectedIndex = 0;
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
final List<Widget> _pages = [
const ScheduleNavigator(),
const EditNavigator(),
const SettingsNavigator(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: _pages,
),
bottomNavigationBar: BottomNavigation(
selectedIndex: _selectedIndex,
onItemTapped: _onItemTapped,
),
);
}
}
Map<String, WidgetBuilder> routes() {
return {
'schedule': (context) => const ScheduleNavigator(),
'edit': (context) => const EditNavigator(),
'settings': (context) => const SettingsNavigator(),
'/notifications': (context) => const NotificationsScreen(),
};
}
Route<dynamic>? generateRoute(RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (context) => const ScheduleNavigator());
case '/schedule':
return MaterialPageRoute(builder: (context) => const ScheduleNavigator());
case '/edit':
return MaterialPageRoute(builder: (context) => const EditNavigator());
case '/settings':
return MaterialPageRoute(builder: (context) => const SettingsNavigator());
case '/notifications':
return MaterialPageRoute(
builder: (context) => const NotificationsScreen());
default:
return MaterialPageRoute(builder: (context) => const ScheduleNavigator());
}
}
and new settings_navigator
class SettingsNavigator extends StatelessWidget {
const SettingsNavigator({super.key});
@override
Widget build(BuildContext context) {
return Navigator(
initialRoute: '/settings',
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/notifications':
return MaterialPageRoute(
builder: (context) => const NotificationsScreen());
default:
return MaterialPageRoute(
builder: (context) => const SettingsScreen());
}
},
);
}
}
also settings_screen:
onTap: () {
Navigator.pushNamed(context, '/notifications');
},
2
Answers
All I realized was that it's useful to use pre-built solutions. To fix my problem, I just used the "go_router" package:
Special thanks to the author of the article for the solution method
First, You have to describe all routes in main.dart. First you have to create routes.
And then in your main.dart, you can add routes like this
If you want to use bottom navigation bar, you have to add route of navigation bottom page to the routes, and you can add your nested pages for navigation bottom bar, inside the navigation bottom bar page