flutter - 在 Flutter 中按下/离开时,TextField 会重新加载 FutureBuilder

标签 flutter dart google-cloud-firestore

用户可以使用 InputChips 输入答案,也可以在 TextField 中手动输入答案。当我尝试使用 InputChips 时,未检测到正确答案。当我尝试手动键入它时,FutureBuilder 在我进入和离开 TextField 时重新加载。是什么原因? Future 函数应该只被调用一次,因为它从 Firestore 中获取一个随机文档,拆分字符串并打乱不同的部分。这是某种形式的测验。

class _buildPhrases extends State<PhrasesSession>{
  TextEditingController _c;
  String _text = "initial";

  @override
  void initState(){
    _c = new TextEditingController();
    super.initState();
  }

  @override
  void dispose(){
    _c?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    final Arguments args = ModalRoute.of(context).settings.arguments;
    var height = MediaQuery.of(context).size.height;
    var width = MediaQuery.of(context).size.width;



    // TODO: implement build
    return Scaffold(
      body: Column(
        children: <Widget>[
          Flexible(flex: 2, child: _buildRest(context),),
          Flexible(flex: 5,
            child: FutureBuilder(
              future: getEverything(args.colName),
              builder: (context, snapshot){
                if(!snapshot.hasData){
                  return Center(child: CircularProgressIndicator(),);
                }else{

                  return Column(
                    children: <Widget>[
                      Flexible(flex: 1, child: Text(snapshot.data[1]),),
                      Divider(),
                      Flexible(flex: 2, child: Container(
                        child: TextField(
                        onChanged: (t){
                            _text += "$t ";
                            if(_c.text == snapshot.data[0]){
                              return print("CORRECT ANSWER");
                            }
                        },
                        controller: _c,
                        textAlign: TextAlign.center,
                          enabled: true,

                      ),
                      ),),
                      Flexible(flex: 3,
                        child: ListView.builder(
                          scrollDirection: Axis.horizontal,
                          itemCount: snapshot.data.length - 2,
                          itemBuilder: (context, index){
                            if(index>snapshot.data.length - 2){
                              return null;
                            }else{
                              return Padding(
                                padding: const EdgeInsets.all(4.0),
                                child: InputChip(
                                  label: Text(snapshot.data[index + 2]),
                                  onPressed: (){
                                    _c.text += "${snapshot.data[index  + 2]} ";
                                  },
                                ),
                              );
                            }
                          },
                        ))
                    ],
                  );
                }
              },
            ),)
        ],
      )
    );
  }
}

最佳答案

让我们分部分解决这个问题。

当我尝试手动键入它时,FutureBuilder 在我进入和离开 TextField 时重新加载。这是什么原因?

这很奇怪,因为当键盘显示或隐藏时,flutter 框架会调用小部件的 build 方法,这种默认行为是 FutureBuilder 重新加载的原因。您应该避免在 build 方法中调用网络方法,我建议您使用 BLoC 模式来处理小部件的状态。

不过,我的 Future 需要从另一条路线传递过来的字符串。查看参数 args = .... 知道我是如何在 initState 中获取它的吗?

好吧,如果您需要 context 实例来获取此 String,您将无法在 initState 方法中访问当前上下文,因为您的小部件不是完全初始化了。在您的情况下解决此问题的一种简单方法(但不是最好的方法)是验证数据是否已从网络获取。

Future _myNetworkFuture; // declare this as member of your stateWidgetClass

Widget build(BuildContext context){
   final Arguments args = ModalRoute.of(context).settings.arguments;
   var height = MediaQuery.of(context).size.height;
   var width = MediaQuery.of(context).size.width;

   // this line says if(_myNetworkFuture == null) do the thing.
   _myNetworkFuture ??= getEverything(args.colName);

   return ...
   Flexible(flex: 5,
        child: FutureBuilder(
          future: _myNetworkFuture,
          builder: (context, snapshot){ 
           // ...
          }
}

使用这种方法,当 flutter 框架调用 build 方法时,如果您已经获取了数据,则不会再次下载数据。但我真的建议你在这种情况下使用 BLoC 模式。

关于flutter - 在 Flutter 中按下/离开时,TextField 会重新加载 FutureBuilder,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56326263/

相关文章:

flutter - 如何在 flutter webview 中打开应用程序链接?

flutter - Flutter-Material Design 2半透明Appbar

Dart:类型 'Null' 不是 Mockito 中类型 'Future<String?>' 的子类型

android - 如何为 Cloud Firestore 自动创建索引?

firebase - 有没有办法立即删除 Firebase 项目?

flutter : how to conditionally add a widget

listview - 我的 listView 只显示一个没有内容的空白页面。我该如何解决?

flutter - Flutter:setState未更新自定义构建的小部件

node.js - 在 firestore 中使用通配符获取查询

flutter - 使用默认值初始化类参数