Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[proposal] Provide a way to close a specific dialog #62960

Open
tolotrasamuel opened this issue Aug 5, 2020 · 18 comments
Open

[proposal] Provide a way to close a specific dialog #62960

tolotrasamuel opened this issue Aug 5, 2020 · 18 comments
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels. P2 Important issues not at the top of the work list team-design Owned by Design Languages team triaged-design Triaged by Design Languages team

Comments

@tolotrasamuel
Copy link

Use case

Currently, there is no way to close a specific alert dialog.

In Flutter, the only way to close a specific dialog is by this dialoge itself like this

showSomeDialog() {
   return showDialog(
       context: context,
       builder: (BuildContext contextPopup) {
         return AlertDialog(
           content: Center(
             child: RaisedButton(
               onPressed: () {
                 Navigator.of(contextPopup).pop();
               },
               child: Text('Close me inside'),
             ),
           ),);
       }
   );
 }

Now what if the parent widget wants to close this dialog? The problem with Navigator.of(context).pop() is that it will close the topmost widget on the Navigation stack, not this specific dialog.

Consider the following reproducible example to illustrate this issue:

Steps to reproduce:

  1. Copy paste the below code in DartPad.dev/flutter

  2. Hit run

  3. Click the Do Api Call button

  4. you should see two popups, one below and one above

  5. After 5 seconds, the one below is desired to close not the one above, instead, the one above closes

How to close the one below and leave the one above open ?

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: CloseSpecificDialog(),
        ),
      ),
    );
  }
}

class CloseSpecificDialog extends StatefulWidget {
  @override
  _CloseSpecificDialogState createState() => _CloseSpecificDialogState();
}

class _CloseSpecificDialogState extends State<CloseSpecificDialog> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: RaisedButton(
        child: Text('Do API call'),
        onPressed: () async {
          showDialogBelow();
          showDialogAbove();
          await Future.delayed(Duration(seconds: 5));
          closeDialogBelowNotAbove();
        },
      )),
    );
  }

  void showDialogBelow() {
    showDialog(
        context: context,
        builder: (BuildContext contextPopup) {
          return AlertDialog(
            content: Container(
              width: 350.0,
              height: 150.0,
              child: Center(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    CircularProgressIndicator(),
                    Text('I am below (you should not see this after 5 sec)'),
                  ],
                ),
              ),
            ),
          );
        });
  }

  void showDialogAbove() {
    showDialog(
        context: context,
        builder: (BuildContext contextPopup) {
          return AlertDialog(
            content: Container(
              height: 100.0,
              child: Center(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    CircularProgressIndicator(),
                    Text('I am above (this should not close)'),
                  ],
                ),
              ),
            ),
          );
        });
  }

  /// This should close the dialog below not the one above
  void closeDialogBelowNotAbove() {
    Navigator.of(context).pop();
  }
}

Proposal

In Android, you just do: dialog.dismiss();

In Flutter, there should be a way to get the reference to each specific dialog
Please make this as a P0 feature request because it is a very basic feature that Android does it so easily and it used so frequently by developers.

@pedromassangocode pedromassangocode changed the title Close a specific dialog from outside of the dialog [proposal] Provide a way to close a specific dialog Aug 5, 2020
@pedromassangocode pedromassangocode added f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. c: proposal A detailed proposal for a change to Flutter c: new feature Nothing broken; request for a new capability labels Aug 5, 2020
@acoutts
Copy link

acoutts commented Aug 6, 2020

I think the root issue here is in the way the current navigator works. You can't push or pop anything below the current active route.

Have you tried using the new navigator 2.0 pages api? I wonder if it's possible to do it in that, where the navigation stack is more malleable.

#45938

@irtza46
Copy link

irtza46 commented Oct 6, 2021

@tolotrasamuel explained very accurately.
Did anyone found any solution till now?

@gslender
Copy link
Contributor

I'd like to see this feature too

@JasonWangex
Copy link

JasonWangex commented Mar 1, 2022

I have the same experience as you. In the end, I chose Overlay to achieve this. The side effect is that this dialog is always at the top level.

@aytunch
Copy link

aytunch commented Mar 1, 2022

The same problem exists in the case of showModalBottomSheet.
In our app, many sheets can be presented on top of each other and we need to have the ability to control which ones get popped.
Navigator.pop() is not a sufficient API for Dialogs and Sheets.

@GiddyNaya
Copy link

Many waiting months later... :/

@justprodev
Copy link

You can play around this

final route = DialogRoute(
    context: context,
    builder: (_)=>MyDialogView(),
    barrierDismissible: false
);

Navigator.of(context).push(route);

// close dialog
Navigator.of(context).removeRoute(route);

Or dive into

Future<T?> showDialog<T>({

@maheshmnj maheshmnj added the f: routes Navigator, Router, and related APIs. label Oct 29, 2022
@Petri-Oosthuizen
Copy link

You can play around this

final route = DialogRoute(
    context: context,
    builder: (_)=>MyDialogView(),
    barrierDismissible: false
);

Navigator.of(context).push(route);

// close dialog
Navigator.of(context).removeRoute(route);

Or dive into

Future<T?> showDialog<T>({

Important to note the following from Navigator.removeRoute:

The removed route is disposed without being notified. The future that had been returned from pushing that routes will not complete.

You'll probably have to play around with completers and the like to get this to work as expected.

@sgehrman

This comment was marked as abuse.

@MelbourneDeveloper
Copy link

Using pop to close a dialog doesn't make much sense. You need to find out if the dialog is currently on screen. It could have already been dismissed, and popping would be like hitting the back button.

@Oooooori
Copy link

any updated?

@sergiotucano
Copy link

any updated?

@danagbemava-nc danagbemava-nc added the customer: crowd Affects or could affect many people, though not necessarily a specific customer. label Jun 1, 2023
@flutter-triage-bot flutter-triage-bot bot added multiteam-retriage-candidate team-design Owned by Design Languages team triaged-design Triaged by Design Languages team labels Jul 8, 2023
@prologikus
Copy link

prologikus commented Aug 5, 2023

Extended showDialog:

Future<T?> showDialogAdvance<T>({
  required WidgetBuilder builder,
  bool barrierDismissible = true,
  bool closePreviousDialog = false,
}) {
  final appServ = AppService.instance;
  final context = appServ.overlayCtx();

  assert(debugCheckHasMaterialLocalizations(context));

  final CapturedThemes themes = InheritedTheme.capture(
    from: context,
    to: Navigator.of(
      context,
      rootNavigator: true,
    ).context,
  );

  if (closePreviousDialog) {
    appServ.closeCurrentDialog();
  }

  final route = DialogRoute<T>(
    context: context,
    builder: builder,
    barrierColor: Colors.black54,
    barrierDismissible: barrierDismissible,
    barrierLabel: null,
    useSafeArea: true,
    settings: null,
    themes: themes,
    anchorPoint: null,
    traversalEdgeBehavior: TraversalEdgeBehavior.closedLoop,
  );

  final future = Navigator.of(context, rootNavigator: true).push<T>(route);

  appServ.setCurrentDialogRoute(route);

  future.whenComplete(() => appServ.setCurrentDialogRoute(null));

  return future;
}

Navigation Service:

class AppService {
  static final instance = AppService._();

  AppService._();

  RootStackRouter? _appRouter;
  RootStackRouter? get appRouter => _appRouter;
  void setRouter(RootStackRouter appRouter) {
    _appRouter ??= appRouter;
  }

  BuildContext overlayCtx() => _appRouter!.navigatorKey.currentContext!;

  /// Dialog
  DialogRoute? _dialogRoute;
  void closeCurrentDialog() {
    if (_dialogRoute != null) {
      Navigator.of(overlayCtx(), rootNavigator: true)
          .removeRoute(_dialogRoute!);
      _dialogRoute = null;
    }
  }

  void setCurrentDialogRoute(DialogRoute? dialogRoute) =>
      _dialogRoute = dialogRoute;
}

@a1573595
Copy link

In my case, I needed to open the bottom sheet while closing the dialog, but the sheet was closed instead.

@Amdian
Copy link

Amdian commented Dec 18, 2023

I have the same experience as you. In the end, I chose Overlay to achieve this. The side effect is that this dialog is always at the top level.

too,i'm hate the getx and flutter

@zoomkoding
Copy link

zoomkoding commented Feb 19, 2024

Please check this issue.

@flutter-triage-bot
Copy link

This issue is missing a priority label. Please set a priority label when adding the triaged-design label.

@flutter-triage-bot flutter-triage-bot bot removed the triaged-design Triaged by Design Languages team label Mar 9, 2024
@HansMuller HansMuller added P2 Important issues not at the top of the work list triaged-design Triaged by Design Languages team labels Mar 13, 2024
@Trung15010802
Copy link

2024 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels. P2 Important issues not at the top of the work list team-design Owned by Design Languages team triaged-design Triaged by Design Languages team
Projects
None yet
Development

No branches or pull requests