简体   繁体   English

Flutter 中没有上下文的 AlertDialog

[英]AlertDialog without context in Flutter

I want to show an AlertDialog when a http get fails.我想在 http 获取失败时显示 AlertDialog。 The function showDialog ( https://api.flutter.dev/flutter/material/showDialog.html ) has the parameter "@required BuildContext context", but I want to call the AlertDialog from my async function getNews(), which hasn't a context value. function showDialog ( https://api.flutter.dev/flutter/material/showDialog.html ) 有参数“@required BuildContext context”,但我想从我的异步 function getNews() 调用 AlertDialog,它没有t 上下文值。

By analogy with Java, where I use null for dialog without an owner, I tried to put context value to null, but it is not accepted.类比Java,我在没有所有者的对话中使用null,我尝试将上下文值设置为null,但不被接受。

This is my code:这是我的代码:

  Future<dynamic> getNews() async {
    dynamic retVal;
    try {
      var response = await http.get(url));
      if (response.statusCode == HttpStatus.ok) {
        retVal = jsonDecode(response.body);
      }
    } catch (e) {
      alertDlg(?????????, 'Error', e.toString());
  }
    return
    retVal;
  }

  static Future<void> alertDlg(context, String titolo, String messaggio) async {
    return showDialog<void>(
        context: context,
        barrierDismissible: false, // user must tap button!
        builder: (BuildContext context) {
        return AlertDialog(
              title: Text(titolo),
        ...
    );
  }

Solution without third-party libraries or storing BuildContext :没有第三方库或存储BuildContext解决方案:

final navigatorKey = GlobalKey<NavigatorState>();

void main() => runApp(
  MaterialApp(
    home: HomePage(),
    navigatorKey: navigatorKey, // Setting a global key for navigator
  ),
);

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: SafeArea(
        child: Center(
          child: Text('test')
        )
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: showMyDialog, // Calling the function without providing it BuildContext
      ),
    );
  }
}

void showMyDialog() {
  showDialog(
    context: navigatorKey.currentContext,
    builder: (context) => Center(
      child: Material(
        color: Colors.transparent,
        child: Text('Hello'),
      ),
    )
  );
}

After setting a global key for navigator ( navigatorKey parameter of MaterialApp class), its current state becomes accessible from any part of the code.为 navigator 设置全局键( MaterialApp类的navigatorKey参数)后,它的当前状态可以从代码的任何部分访问。 We can pass its context to the showDialog function.我们可以将其上下文传递给showDialog函数。 Make sure not to use it before the first frame is built, otherwise the state will be null.确保在第一帧构建之前不要使用它,否则状态将为空。

Basically, dialogs are just another type of routes like MaterialPageRoute or CupertinoPageRoute - they are all derived from the ModalRoute class and their instances are pushed into NavigatorState .基本上,对话框只是另一种类型的路由,如MaterialPageRouteCupertinoPageRoute - 它们都派生自ModalRoute类,并且它们的实例被推送到NavigatorState Context is only needed to get the current navigator's state.上下文只需要获取当前导航器的状态。 A new route can be pushed without having a context if we have a global navigator key:如果我们有全局导航键,则可以在没有上下文的情况下推送新路由:

navigatorKey.currentState.push(route)

Unfortunately, _DialogRoute class (...\\flutter\\lib\\src\\widgets\\routes.dart) used in showDialog function is private and unaccessible, but you make your own dialog route class and push it into the navigator's stack.不幸的是, showDialog函数中使用的_DialogRoute类 (...\\flutter\\lib\\src\\widgets\\routes.dart) 是私有的且无法访问,但是您可以创建自己的对话框路由类并将其推送到导航器的堆栈中。

UPDATE : Navigator.of method has been updated and it's no longer needed to pass subtree context.更新Navigator.of方法已更新,不再需要传递子树上下文。

The accepted answer is wrong.接受的答案是错误的。

The dialog only needs the context to access it through an inherited navigateState.对话框只需要上下文就可以通过继承的navigateState 访问它。 You can make your own modified dialog, or use my lib to do this.您可以制作自己的修改对话框,或使用我的库来执行此操作。

https://pub.dev/packages/get https://pub.dev/packages/get

With it you can open dialog from anywhere in your code without context by doing this:有了它,您可以通过执行以下操作从代码中的任何位置打开对话框,而无需上下文:

Get.dialog(SimpleDialog());

如果使用await,则在调用getNews 时捕获异常,否则使用Future 的catchError 属性。

So you need a BuildContext to create a dialog but you don't have access to it.因此,您需要一个BuildContext来创建对话框,但您无权访问它。 That's a common problem, you can refer to this StackOverflow question for one of the approaches to solve it (create a static dialog and show it from wherever you need).这是一个常见问题,您可以参考此 StackOverflow 问题以获取解决它的方法之一(创建一个静态对话框并从您需要的任何位置显示它)。

Another approach you may consider is to pass the context when creating an async method or object as an argument.您可能会考虑的另一种方法是在创建异步方法或对象作为参数时传递上下文。 Make sure you null it when you're done.确保在完成后将其归零。

Or you can make a flag (boolean) which becomes 'true' under a certain condition, and in one of the build() methods you always check that flag, and if it's 'true' - do your thing (show a dialog for instance).或者您可以制作一个在特定条件下变为“真”的标志(布尔值),并且在build()方法之一中,您始终检查该标志,如果它是“真” - 做您的事(例如显示一个对话框)。

Easiest way to show alert anywhere: Use this package link and enter these lines wherever you want to show alert:在任何地方显示警报的最简单方法:使用此 package链接并在要显示警报的任何位置输入以下行:

QuickAlert.show( context: context, type: QuickAlertType.error, text: 'Error Message');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM