如何在futurebuilder中显示对话框?

时间:2019-07-04 22:11:23

标签: flutter dart

如果我在futurebuilder中收到错误,我想显示一个对话框。

如果收到错误消息,我想显示一个对话框并强迫用户单击按钮,以便可以将他重定向到另一页面。

问题似乎是在构建窗口小部件时无法显示对话框。

FutureBuilder(
      future: ApiService.getPosts(),
      builder: (BuildContext context, AsyncSnapshot snapShot) {
        if (snapShot.connectionState == ConnectionState.done) {
          if (snapShot.data.runtimeType == http.Response) {
            var message =
              json.decode(utf8.decode(snapShot.data.bodyBytes));

    showDialog(
     context: context,
     barrierDismissible: false,
     builder: (context) {
       return AlertDialog(
        content: Text(message),
        actions: <Widget>[
          FlatButton(
            child: Text("Ok"),
            onPressed: () => null",
          )
        ],
      );
    });
  }
     return ListView.separated(
            separatorBuilder: (BuildContext context, int index) {
              return Divider(
                color: Colors.grey,
                height: 1,
              );
            },
            itemBuilder: (BuildContext context, int index) {
              return _buildPostCard(index);
            },
            itemCount: snapShot.data.length,
          );
     return Center(
          child: CircularProgressIndicator(),
        );
      },
    )

如果我仅返回AlertDialog,它将起作用。但由于barrierDismissible属性,我需要showDialog。

有人知道这是否可能吗? 另外,这是处理我想要的东西的好方法吗?

谢谢

更新

为进一步参考,工作中的一位朋友提供了解决方案。

为了做我想要的,我必须决定将哪个未来传递给futureBuilder。

Future<List<dynamic>> getPostsFuture() async { 
try {
    return await ApiService.getPosts();
  } catch (e) {

     await showDialog(
 context: context,
 barrierDismissible: false,
 builder: (context) {
   return AlertDialog(
    content: Text(message),
    actions: <Widget>[
      FlatButton(
        child: Text("Ok"),
        onPressed: () => null",
      )
    ],
  );
});
  }
}

}

然后在futureBuilder中,我会打电话

FutureBuilder(
  future: getPostsFuture(),

谢谢

3 个答案:

答案 0 :(得分:10)

为避免在使用setState() or markNeedsBuild() called during build时出现showDialog错误,请像这样将其包装到Future.delayed中:

Future.delayed(Duration.zero, () => showDialog(...));

答案 1 :(得分:0)

builder参数希望您返回Widget。 showDialog是Future。 所以你不能退货。
您将Dialog显示在其他窗口小部件的顶部,则无法从需要窗口小部件的构建方法中将其返回。
您想要的可以通过以下方式实现。
收到错误时,在UI上显示一个对话框,并为构建器返回一个容器。修改您的代码为此:

if (snapShot.data.runtimeType == http.Response) {
          var message =
          json.decode(utf8.decode(snapShot.data.bodyBytes));

          showDialog(
              context: context,
              barrierDismissible: false,
              builder: (context) {
                return AlertDialog(
                  content: Text(message),
                  actions: <Widget>[
                    FlatButton(
                        child: Text("Ok"),
                        onPressed: () => null",
                    )
                  ],
                );
              });
          return Container();
        }

答案 2 :(得分:0)

在构建过程中调用

setState()或markNeedsBuild()。 允许使用此异常是因为该框架在子代之前构建父窗口小部件,这意味着将始终构建脏后代。否则,框架在此构建阶段可能不会访问此小部件。

因此,为了避免使用Future回调,它会像这样EventQueue.添加呼叫:

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  Future futureCall() async {
    await Future.delayed(Duration(seconds: 2));
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: futureCall(),
      builder: (_, dataSnapshot) {
        if (dataSnapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        } else {
          Future(() {
            showDialog(
                context: context,
                builder: (context) => AlertDialog(
                      title: Text('Employee Data'),
                      content: Text('Do you want to show data?'),
                      actions: <Widget>[
                        FlatButton(
                            onPressed: () =>
                                Navigator.of(context).pop('No'),
                            child: Text('NO')),
                        FlatButton(
                            onPressed: () =>
                                Navigator.of(context).pop('Yes'),
                            child: Text('YES'))
                      ],
                    ));
          });
          return Container();
        }
      },
    );
  }
}