How to get context in the any function of StatelessWidget?
Asked Answered
A

3

10

We want to show an AlertDialog after some asynchronous processing such as network processes.

When calling 'showAlertDialog ()' from an external class, I want to call it without context. Is there a good way?

class SplashPage extends StatelessWidget implements SplashView {
  BuildContext _context;
  @override
  Widget build(BuildContext context) {
    this._context = context;
    ...
  }

I've considered the above method, but I'm worried about side issues.

Help

My current code

class SplashPage extends StatelessWidget implements SplashView {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: MyStoreColors.eats_white1_ffffff,
      body: Center(
        child: new SvgPicture.asset('assets/ic_splash.svg'),
      ),
    );
  }

  @override
  void showAlertDialog() {

    showDialog<void>(
      context: /*How to get context?*/,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Not in stock'),
          content: const Text('This item is no longer available'),
          actions: <Widget>[
            FlatButton(
              child: Text('Ok'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }

  @override
  void moveToHomeContainer() {
  }

  @override
  void moveToLoginContainer() {
  }
}

Agraffe answered 24/10, 2019 at 14:4 Comment(4)
and where will you use showAlertDialog? You could pass a context as parameterFluoresce
Yea, why are you not using showAlertDialog(BuildContext context) ?Beldam
I try to use an architecture similar to MVP. In this page, I want to check the app version when the view is bound to the presenter. And I want to output the error message about the version check to view.showAlertDialog() in the presenter.Agraffe
Are you talking about calling presenter.checkAppVersion(context) in build()?Agraffe
C
3

You should trigger rebuild when the async event complete, either convert your widget to StatefulWidget and call setState() or use a state management solution like Bloc.

For example using StatefulWidget your code will look like this:

class SplashPage extends StatefulWidget {
  @override
  State<SplashPage> createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage> implements SplashView {

  bool _asynOpDone = false;

  /// Call this when the async operation is done.
  void _onAsynOpDone() => setState(() => _asyncOpDone = true);

  @override
  Widget build(BuildContext context) {
    if (_asyncOpDone) showAlertDialog(context);

    return Scaffold(
      ...,
      ///
    );
  }

  @override
  void showAlertDialog(BuildContext context) {
    showDialog<void>(
      context: context,
      builder: ...,
    );
  }
}
Castara answered 24/10, 2019 at 21:37 Comment(1)
This page is an intro screen with only one image view. Once built, views do not need to be rebuilt. By the way, should I use StatefulWidget to bring up an AlertDialog? I thought there was another good way to ask.Agraffe
M
7

To show an AlertDialog you need the context, but in StatelessWidget you do not have access to it directly as in StatefulWidget.

Few options are [1]:

  • passing it as GlobalKey [2]
  • passing build context as parameter to any other function inside StatelessWidget
  • use a service to inject the dialog without context [3]

Cheers.

Mikesell answered 31/12, 2020 at 19:15 Comment(0)
C
3

You should trigger rebuild when the async event complete, either convert your widget to StatefulWidget and call setState() or use a state management solution like Bloc.

For example using StatefulWidget your code will look like this:

class SplashPage extends StatefulWidget {
  @override
  State<SplashPage> createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage> implements SplashView {

  bool _asynOpDone = false;

  /// Call this when the async operation is done.
  void _onAsynOpDone() => setState(() => _asyncOpDone = true);

  @override
  Widget build(BuildContext context) {
    if (_asyncOpDone) showAlertDialog(context);

    return Scaffold(
      ...,
      ///
    );
  }

  @override
  void showAlertDialog(BuildContext context) {
    showDialog<void>(
      context: context,
      builder: ...,
    );
  }
}
Castara answered 24/10, 2019 at 21:37 Comment(1)
This page is an intro screen with only one image view. Once built, views do not need to be rebuilt. By the way, should I use StatefulWidget to bring up an AlertDialog? I thought there was another good way to ask.Agraffe
G
2

You can apply Builder pattern concept to simplify this.

There is a little example here.

button_builder.dart

Gimel answered 28/1, 2022 at 0:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.