用户可以使用 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/