SimonartM
SimonartM

Reputation: 688

Flutter: showGeneralDialog does not share a context with the location that showGeneralDialog is originally called from

Problem:

My showGeneralDialog-creation method looks like this: (I'm animating the onShow and onPop of the dialog, that's why I use the transitionbuilder instead of the pagebuilder)

  void _showSignOutAlert(BuildContext context) {
    showGeneralDialog(
      barrierColor: Colors.black.withOpacity(0.5),
      transitionBuilder: (context, a1, a2, widget) {
        return Transform.scale(
          scale: a1.value,
          child: Opacity(
            opacity: a1.value,
            child: CustomWidget(),
          ),
        );
      },
      transitionDuration: Duration(milliseconds: 250),
      barrierDismissible: true,
      context: context,
      pageBuilder: (context, animation1, animation2) {
        return null;
      },
    );
  }

I'm calling _showSignOutAlert() from a StatelessWidget passing along the StatelessWidget-context in the parameter.

I'm using the Provider-package and defined the ChangeNotifierProvider-builder above the StatelessWidget which calls the _showSignOutAlert()

When trying to access the Provider from the CustomWidget created by showGeneralDialog(), it's says it couldn't find the Provider.

From the flutter docs about showGeneralDialog():

This function takes a pageBuilder which is used to build the primary content of the route (typically a dialog widget). Content below the dialog is dimmed with a [ModalBarrier]. The widget returned by the pageBuilder does not share a context with the location that showGeneralDialog is originally called from. Use a [StatefulBuilder] or a custom [StatefulWidget] if the dialog needs to update dynamically. The pageBuilder argument can not be null.

Question:

I don't really get how I should proceed to be able to access the Provider from the CustomWidget?

Upvotes: 3

Views: 3294

Answers (3)

Gemu
Gemu

Reputation: 629

put useRootNavigator to false

https://api.flutter.dev/flutter/widgets/showGeneralDialog.html

The useRootNavigator argument is used to determine whether to push the dialog to the Navigator furthest from or nearest to the given context. By default, useRootNavigator is true and the dialog route created by this method is pushed to the root navigator.

Upvotes: 2

DJafari
DJafari

Reputation: 13535

correct way :

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

  showGeneralDialog(
    barrierColor: Colors.black.withOpacity(0.5),
    transitionBuilder: (context, a1, a2, widget) {
      return Transform.scale(
        scale: a1.value,
        child: Opacity(
          opacity: a1.value,
          child: widget,
        ),
      );
    },
    transitionDuration: Duration(milliseconds: 250),
    barrierDismissible: true,
    context: context,
    pageBuilder: (context, animation1, animation2) {
      return themes.wrap(Builder(
        builder: (context) => CustomWidget(),
      ));
    },
  );
}

pay attention to :

CapturedThemes and themes.wrap

Upvotes: 2

SimonartM
SimonartM

Reputation: 688

I did manage to pass the context, by doing so:

  void _showSignOutAlert(BuildContext superContext) {
    showGeneralDialog(
      barrierColor: Colors.black.withOpacity(0.5),
      transitionBuilder: (context, a1, a2, widget) {
        return Transform.scale(
          scale: a1.value,
          child: Opacity(
            opacity: a1.value,
            child: CustomWidget(superContext: superContext),
          ),
        );
      },
      transitionDuration: Duration(milliseconds: 250),
      barrierDismissible: true,
      context: superContext,
      pageBuilder: (context, animation1, animation2) {
        return null;
      },
    );
  }

And then using the superContext in the CustomWidget to call Provider.of<State>(superContext)

But if anyone has another solution, I'd gladly hear it

Upvotes: 1

Related Questions