美文网首页Flutter
Flutter更新showDialog中的内容

Flutter更新showDialog中的内容

作者: 书写不简单 | 来源:发表于2019-01-16 15:35 被阅读33次

    很多人在用showDialog的时候应该都遇到过这个问题,使用showDialog后,通过setState()无法更新当前dialog。其实原因很简单,因为dialog其实是另一个页面,准确地来说是另一个路由,因为dialog的关闭也是通过navigator来pop的,所以它的地位跟你当前主页面一样。这个概念一定要明确,因为无论在Android或iOS中,daliog都是依附于当前主页面的一个控件,但是在Flutter中不同,它是一个新的路由。所以使用当前主页面的setState()来更新,当然没法达到你要的效果。

    showDialog方法的Api中也明确说明了这一点,dialog所持有的context已经变了:

    This widget does not share a context with the location that showDialog is originally called from. Use a [StatefulBuilder] or a custom [StatefulWidget] if the dialog needs to update dynamically.

    所以我们有两种方法来解决这个问题,一种是使用StatefulBuilder,另一种是使用自定义的StatefulWidget。

    StatefulBuilder

    很多人使用StatefulBuilder依然达不到更新的效果,是因为你用错了setState()方法。

    源码中关于builder的注释中有一句:

    Typically the parent's build method will construct a new tree of widgets and so a new Builder child will not be [identical] to the corresponding old one.

    就像我们上面说的那样,这个builder构建的控件,不会响应老页面的任何操作,因为它们是两个互不影响的路由控制的。

    showDialog(
        context: context,
        builder: (context) {
            String label = 'test';
            return StatefulBuilder(
                builder: (context, state) {
                    print('label = $label');
                    return GestureDetector(
                        child: Text(label),
                        onTap: () {
                            label = 'test8';
                            print('onTap:label = $label');
                            // 注意不是调用老页面的setState,而是要调用builder中的setState。
                            //在这里为了区分,在构建builder的时候将setState方法命名为了state。
                            state(() {});  
                        },
                    );
                },
             );
        });
    
    

    在构建builder的时候,返回给了我们两个参数,BuildContext context 和 StateSetter setState,我们可以点进源码,StatefulWidgetBuilder的注释写的很清楚:

    Call [setState] to schedule the [StatefulBuilder] to rebuild.

    所以我们要调用的是builder返回给我们的setState,而不是老页面的setState。

    自定义的StatefulWidget

    用StatefulWidget就容易多了,思路就是将控制刷新的变量放到我们自定义的StatefulWidget的State中:

    showDialog(
        context: context,
        builder: (context) {
            String label = 'test';
            return DialogContent(
                label: label,
            );
        });
     
    class DialogContent extends StatefulWidget {
      final String label;
     
      DialogContent({Key key, this.label}) : super(key: key);
     
      @override
      State<StatefulWidget> createState() => DialogContentState();
    }
     
    class DialogContentState extends State<DialogContent> {
      String label = '';
     
      @override
      void initState() {
        super.initState();
        label = widget.label;
      }
     
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          child: Text(label),
          onTap: () {
            setState(() {
              label = 'test9';
            });
          },
        );
      }
    }
    

    现在网上的教程都是说这么写的,比起用builder要麻烦一些,但是也更容易理解,不容易出错。
    参考.

    相关文章

      网友评论

        本文标题:Flutter更新showDialog中的内容

        本文链接:https://www.haomeiwen.com/subject/kvymdqtx.html