skip to Main Content

I start out with a top-level scaffold created inside a stateful widget. The app navigates automatically to the home route, and the appbar minus back button displays correctly.

Here is the main code

Widget build(BuildContext context) {
  return MultiProvider(
    providers: [
      ChangeNotifierProvider<MyAquariumManagerModel>(
        create: (_) => MyAquariumManagerModel(manageSession),
      ),
      ChangeNotifierProvider<MyAquariumManagerFacilityModel>(
        create: (_) => MyAquariumManagerFacilityModel(manageSession),
      ),
      ChangeNotifierProvider<MyAquariumManagerTanksModel>(
        create: (_) => MyAquariumManagerTanksModel(manageSession),
      ),
      ChangeNotifierProvider<MyAquariumManagerSearchModel>(
        create: (_) => MyAquariumManagerSearchModel(manageSession),
      ),
    ],
    child: MaterialApp(
      title: kProgramName,
      theme: aquarium_manager_theme,
      home: ScaffoldController(),
    ),
  );
}

And the top-level ScaffoldController

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text(kProgramName),
    ),
  body: Navigator(
      initialRoute: '/',
      onGenerateRoute: (RouteSettings settings) {
        WidgetBuilder builder;
        switch (settings.name) {
          case '/':
            builder = (BuildContext _) => MyAquariumManagerLoginController(); <-there is no other scaffold here; it depends on the top-level one (this one right here)
            break;
          case '/homescreen':
            builder = (BuildContext _) => AquariumManagerHomeScreenController(); <- there is also no other scaffold here, we never navigate here. MyAquariumManagerLoginController just returns the widgets of this controller.
            break;
          case '/searchscreen':
            builder = (BuildContext _) => MyAquariumManagerSearchController();
            break;
          case '/facilitiesscreen':
            builder = (BuildContext _) => MyAquariumManagerFacilitiesController();
            break;
          case '/tanksscreen':
            builder = (BuildContext _) => MyAquariumManagerTankController(arguments: {
              'incomingRack_Fk': null,
              'incomingTankPosition': null,
            },);
            break;
          default:
            throw Exception('Invalid route: ${settings.name}');
        }
        return MaterialPageRoute(builder: builder, settings: settings);
      },
    ),
  );
}

I navigate to other screens in this fashion

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => MyAquariumManagerFacilitiesController(),
    settings: RouteSettings(name: '/facilitiesscreen'),
  ),
)

and the top-level appbar is still there, but there is no back button. Some of these screens happen to have their own scaffolds and their appbar appears below the top-level scaffold’s appbar but this appbar does display a back button.

Ideally, I want to remove the scaffolds from the individual routes and just keep the top-level scaffold but how can I get it to display its own back button?

I tried forcing the button to appear and then popping the route stack and I always get a black screen, so for some reason, the top-level scaffold isn’t aware of what’s on the route stack, but I don’t know why. For the few routes that have their own scaffold, their back buttons work, so somewhere in flutter, it knows what routes are on the stack.

2

Answers


  1. Chosen as BEST ANSWER

    The correct answer is to make the navigator routes part of the material app and to ensure each screen gets its own scaffold.

    Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
            ChangeNotifierProvider<MyAquariumManagerModel>(
              create: (_) => MyAquariumManagerModel(manageSession),
            ),
            ChangeNotifierProvider<MyAquariumManagerFacilityModel>(
              create: (_) => MyAquariumManagerFacilityModel(manageSession),
            ),
            ChangeNotifierProvider<MyAquariumManagerTanksModel>(
              create: (_) => MyAquariumManagerTanksModel(manageSession),
            ),
            ChangeNotifierProvider<MyAquariumManagerSearchModel>(
              create: (_) => MyAquariumManagerSearchModel(manageSession),
            ),
          ],
          child: MaterialApp(
            title: kProgramName,
            theme: aquarium_manager_theme,
            home: MyAquariumManagerLoginController(),
            onGenerateRoute: (RouteSettings settings) {
              WidgetBuilder builder;
              switch (settings.name) {
                case '/':
                  builder = (BuildContext _) => MyAquariumManagerLoginController();
                  break;
                case '/homescreen':
                  builder = (BuildContext _) => AquariumManagerHomeScreenController();
                  break;
                case '/searchscreen':
                  builder = (BuildContext _) => MyAquariumManagerSearchController();
                  break;
                case '/facilitiesscreen':
                  builder = (BuildContext _) => MyAquariumManagerFacilitiesController();
                  break;
                case '/tanksscreen':
                  builder = (BuildContext _) => MyAquariumManagerTankController(
                    arguments: {
                      'incomingRack_Fk': null,
                      'incomingTankPosition': null,
                    },
                  );
                  break;
                default:
                  throw Exception('Invalid route: ${settings.name}');
              }
              return MaterialPageRoute(builder: builder, settings: settings);
            },
          ),
        );
      }
    

  2. BackButton "AppBar, which automatically uses a BackButton in its AppBar.leading slot when the Scaffold has no Drawer and the current Route is not the Navigator’s first route."

    In your case, it is actually the first route, because your navigation happens to be in the body of your main Scaffold – so it is a nested one. If I recall correctly, inbuilt BackButton does not allow you to customize it the way you want it. Instead, you can build your custom back button and disable default one from AppBar.

    Although, I personally would just use a package from pub.dev like go_router which makes it very convenient to work with nested routes, and the navigation overall.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search