is there any way in flutter to persist dialog when moving from one screen to another?

97 views Asked by At

I have a two screens. Screen A and Screen B. I have a button on Screen A. when I click on it. It shows a dialog. after that I have a used Future.delayed(). when duration is over I move to the Screen B. but dialog also closes here. I want the dialog to be remain open and should no be closed until I called. context.pop() method;

I am using go_router package in my app.

This is how my onPressed look like

showGeneralDialog(context: context,barrierColor: Colors.white.withOpacity(0),
pageBuilder: (context, animation, secondaryAnimation) => SplashView(),
await Future.delayed(Duration(seconds: 2));
GoRouter.of(context).go('/home');
2

There are 2 answers

0
Texv On BEST ANSWER

You can do that by wrapping the Dialog with an Overlay widget and placing that widget in the global (app level) section outside your class to make it independent of the route changes, and create a function to show/hide the dialog.

You may see a demo here. As an added bonus I also created a function to change the text inside the dialog when navigation is complete and to show or hide the "close dialog" button conditionally.

  Define Widget and Function globally:
  
  static void setDialogText(String newText, bool show) {
    dialogText = newText;
    showCloseButton = show;

    if (isOpen) {
      _overlayEntry?.markNeedsBuild();
    }
  }

  static void show(BuildContext context) {
    isOpen = true;
    _overlayEntry = OverlayEntry(
      builder: (context) {
        return Center(
          child: Dialog(
            backgroundColor: Colors.grey,
            child: SizedBox(
              height: 60.0,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Text(
                    dialogText,
                  ),
                  !showCloseButton
                      ? const SizedBox.shrink()
                      : ElevatedButton(
                          onPressed: () {
                            // Close the dialog
                            isOpen = false;
                            _overlayEntry?.remove();
                          },
                          child: const Text('Close Dialog')),
                ],
              ),
            ),
          ),
        );
      },
    );

    Overlay.of(context).insert(_overlayEntry!);
  }
  
  Inside a class call it like this: 
  
  onPressed: () {
            OverlayDialog.show(context);
            Future.delayed(const Duration(seconds: 3), () {
              if (OverlayDialog.isOpen) {
                Navigator.of(context).push(
                  MaterialPageRoute(builder: (context) => const ScreenB()),
                );
                OverlayDialog.setDialogText('Welcome to ScreenB!', true);
              }
            });
          },

1
Mahesh Gv On

Here's an example, you can do this,

    import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ScreenA(),
    );
  }
}

class ScreenA extends StatefulWidget {
  @override
  _ScreenAState createState() => _ScreenAState();
}

class _ScreenAState extends State<ScreenA> {
  bool isDialogOpen = false;

  void openDialog() {
    setState(() {
      isDialogOpen = true;
    });
  }

  void closeDialog() {
    setState(() {
      isDialogOpen = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Screen A'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                openDialog();
                // Use Future.delayed here to navigate to Screen B after a delay
                Future.delayed(Duration(seconds: 2), () {
                  Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => ScreenB()),
                  );
                });
              },
              child: Text('Show Dialog and Navigate to Screen B'),
            ),
            if (isDialogOpen) MyDialog(closeDialog: closeDialog),
          ],
        ),
      ),
    );
  }
}

class ScreenB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Screen B'),
      ),
      body: Center(
        child: Text('Screen B Content'),
      ),
    );
  }
}

class MyDialog extends StatelessWidget {
  final Function closeDialog;

  MyDialog({required this.closeDialog});

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('My Dialog'),
      content: Text('This is a custom dialog.'),
      actions: <Widget>[
        ElevatedButton(
          onPressed: () {
            closeDialog();
          },
          child: Text('Close Dialog'),
        ),
      ],
    );
  }
}