【问题标题】:AlertDialog without context in FlutterFlutter中没有上下文的AlertDialog
【发布时间】:2019-10-10 08:29:21
【问题描述】:

我想在 http 获取失败时显示 AlertDialog。函数 showDialog (https://api.flutter.dev/flutter/material/showDialog.html) 具有参数“@required BuildContext context”,但我想从我的异步函数 getNews() 调用 AlertDialog,它没有上下文值。

与 Java 类比,我在没有所有者的对话框中使用 null,我尝试将上下文值设置为 null,但不被接受。

这是我的代码:

  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),
        ...
    );
  }

【问题讨论】:

  • StatefulWidget 传递您的Build 上下文,您将在其中显示对您的getNews() 函数的http 响应。
  • 你能举个例子吗?我尝试将上下文传递给我的新小部件。它没有给出任何错误,但也没有显示任何警报
  • 绕过 null 没有得到任何编译时错误但得到相同的 Failed assertion: line 'context != null': is not true.

标签: dart flutter dialog


【解决方案1】:

接受的答案是错误的。

对话框只需要上下文就可以通过继承的 navigateState 访问它。 您可以制作自己的修改对话框,或使用我的库来执行此操作。

https://pub.dev/packages/get

使用它,您可以在代码中的任何位置打开对话框,而无需执行以下操作:

Get.dialog(SimpleDialog());

【讨论】:

  • 这是不可能的。您可能忘记将“Get”添加到您的 MaterialApp。将其更改为 GetMaterialApp,一切正常。
  • 喜欢这个 GetMaterialApp.dialog(SimpleDialog());
  • 我试过这个 GetMaterialApp(title: UtilString.submit);出现编译时错误。
  • 不,在你的主文件上
  • 如果不需要,不要强制使用第三方库。用final navigatorKey = GlobalKey&lt;NavigatorState&gt;();查看答案
【解决方案2】:

没有第三方库或存储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'),
      ),
    )
  );
}

在为导航器设置全局键(MaterialApp 类的navigatorKey 参数)后,可以从代码的任何部分访问其当前状态。我们可以将其上下文传递给showDialog 函数。确保在构建第一帧之前不要使用它,否则状态将为空。

基本上,对话框只是另一种类型的路由,如MaterialPageRouteCupertinoPageRoute - 它们都派生自ModalRoute 类,并且它们的实例被推入NavigatorState。上下文只需要获取当前导航器的状态。如果我们有一个全局导航键,则可以在没有上下文的情况下推送新路由:

navigatorKey.currentState.push(route)

不幸的是,showDialog 函数中使用的 _DialogRoute 类 (...\flutter\lib\src\widgets\routes.dart) 是私有且不可访问的,但是您创建了自己的对话路由类并将其推送到导航器的堆栈。

更新Navigator.of 方法已更新,不再需要传递子树上下文。

【讨论】:

  • 伟大的黑客! .overlay 拯救了我的一天! (我发现如果直接使用navigatorKey.currentState.context,它不会起作用,因为showDialog需要一个上下文below Navigator上下文。)
  • 使用navigatorKey.currentContext怎么样?好像行得通,但我不确定与currentState.overlay.context相比是否存在潜在问题?
  • 未处理的异常:NoSuchMethodError:在 null 上调用了 getter 'overlay'。 E/flutter(30999):接收者:null E/flutter(30999):尝试调用:overlay
  • 未处理的异常:NoSuchMethodError:在 null 上调用了 getter 'overlay'。出错
  • @MagnusW 没错,现在可以传递导航器状态的上下文,因为 Navigator.of 方法已更新。
【解决方案3】:

因此,您需要BuildContext 来创建对话框,但您无权访问它。这是一个常见的问题,您可以参考this StackOverflow question 来了解其中一种解决方法(创建一个静态对话框并从您需要的任何地方显示它)。

您可以考虑的另一种方法是在创建异步方法或对象作为参数时传递上下文。完成后确保将其设为空。

或者您可以制作一个在特定条件下变为“真”的标志(布尔值),并在 build() 方法之一中始终检查该标志,如果它为“真” - 做你的事(显示例如对话框)。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-21
      • 1970-01-01
      • 2021-03-20
      • 2023-03-13
      • 2020-03-17
      • 2020-11-17
      • 2019-09-16
      • 1970-01-01
      相关资源
      最近更新 更多