0

In my app, I have some areas where I can open a new page on top of the current, that allow to edit data. Once editing is done, I want to close the page (i.e. via Navigator.pop(context);), and also show a Snackbar after closing (i.e. via ScaffoldMessenger.of(context).showSnackBar('X has been saved')). I am using a ScaffoldMessenger for that.

However, if after closing the edit-page only the top-route remains, the Snackbar will not be shown. If I open any other page fast enough, it will be shown there for the remaining time though. So it was triggered, it is just not shown on the top-route. Also, if I open the edit-page not from the top-route, but from any other page that was already opened on top, the Snackbar will show normally after closing the edit-page.

If I open a Snackbar directly on the top-route, it also works fine. So instead of opening the Snackbar from the edit-page, I could technically return the message and then trigger the Snackbar. But I would prefer not to to pass data around and call functionality at several places, but just call the method at one place (where it belongs).

I can reproduce this behaviour on a newly created App, just need to replace the _MyHomePageState with the following code. What am I doing wrong here?

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey<ScaffoldMessengerState> _globalScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
  @override
  Widget build(BuildContext context) {
    return ScaffoldMessenger(
      key: _globalScaffoldMessengerKey,
      child: Scaffold(
        body: Center(
          child: ElevatedButton(
            onPressed: () {
              Navigator.push<bool>(context, MaterialPageRoute(builder: (context) => const SubPage()));
            },
            child: const Text("Open Subpage"),
          ),
        ),
      ),
    );
  }
}

class SubPage extends StatelessWidget {
  const SubPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
            ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Hello Snackbar')));
          },
          child: const Text("Close Subpage"),
        ),
      ),
    );
  }
}
Christian
  • 558
  • 2
  • 13

1 Answers1

1

Remove the scaffold Messenger widget from the first page

import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
                context, MaterialPageRoute(builder: (context) => const SubPage()));
          },
          child: const Text("Open Subpage"),
        ),
      ),
    );
  }
}

class SubPage extends StatelessWidget {
   const SubPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
            ScaffoldMessenger.of(context)
                .showSnackBar(SnackBar(content: Text('Hello Snackbar')));
          },
          child: const Text("Close Subpage"),
        ),
      ),
    );
  }
}

I checked this code and it shows snackbar in the page that exists after popping the subpage

Kaushik Chandru
  • 15,510
  • 2
  • 12
  • 30
  • Thank you, but as written in the question, I'm aware I could do that, but I do not want to do this. As edit pages are opened from several places, I'd have to copy&paste this code across my app. This looks like a very bad workaround to me. – Christian Jun 24 '22 at 14:58
  • That would work, but doesn't this totally invalidate the point of the ScaffoldMessenger as described here https://docs.flutter.dev/release/breaking-changes/scaffold-messenger ? With this change, the Snackbar is again targeted at exactly one Scaffold. – Christian Jun 24 '22 at 15:41
  • Edited again. This has no dependencies like you expected – Kaushik Chandru Jun 24 '22 at 15:42
  • That wasn't my point. Let's say i've got my root-page, then open a detail-page, then open an edit-page. Once I close the edit-page and trigger the SnackBar like that, it will not be shown until I close the detail-page, as the scaffold on the root-page is targeted. I would need to assign a separate GlobalKey to the scaffold in the details-page, and upon closing the edit-page I would need to target that specific scaffold. And at that point the features from the ScaffoldMessenger like transitioning betweens scaffolds will not work anymore. – Christian Jun 24 '22 at 15:51
  • Snackbar belongs to a scaffold, you need to reference a scaffold for sure. You can probably try adding a variable to save the top most page and invoke a snackbar on that scaffold – Kaushik Chandru Jun 24 '22 at 15:54
  • As I understand it, that was the case before ScaffoldMessenger. With it, that is no longer necessary. At least thats how I understand the page I linked earlier, and that how it works for me for all pages but the root-page... – Christian Jun 24 '22 at 16:03
  • Edited my answer again. Checked the codes and it shows snackbar in the first screen after popping the subpage – Kaushik Chandru Jun 24 '22 at 16:48
  • Indeed it does, and also in my real use case. Thank you! – Christian Jun 24 '22 at 17:21