FutureBuilder中如何正确使用setState?
How to use setState in FutureBuilder properly?
我正在制作一个页面,其中包含一些相互交互的保管箱和一个 Futurebuilder 包装的 ListView。
我正在调用 'setState',当 Dropbox 发生变化并且复选框被点击时。
但是因为checkbox的onChanged中的setState,Futurebuilder一直被调用,ListView被重建。
因此,当像下面的视频一样单击复选框时,整个 Listview 都会闪烁。
我想保留 Listview and update only 复选框。
有没有人可以帮助我?
谢谢。
完整代码为
class _StatefulDialogWidgetState extends State<StatefulDialogWidget> {
....
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Dropdown's
Dropdown(0, widget.ReceiveArgs, _lListOfDepthList),
Dropdown(1, widget.ReceiveArgs, _lListOfDepthList),
Dropdown(2, widget.ReceiveArgs, _lListOfDepthList),
Dropdown(3, widget.ReceiveArgs, _lListOfDepthList),
Dropdown(4, widget.ReceiveArgs, _lListOfDepthList),
// Listview with FutureBuilder
AptListview(),
],
);
}
列表视图代码
Widget AptListview() {
return FutureBuilder<List<String>>(
future: AptNameListView(widget.ReceiveArgs),
builder: (context, snapshot) {
if (_bLastDepth == false) {
return Text("Select Address");
} else {
if (snapshot.hasData == false || snapshot.data.isEmpty == true) {
return CircularProgressIndicator();
} else {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: _AptNameList.length,
itemBuilder: (context, index) {
//return new Text("${_AptName[index]}");
return CheckboxListTile(
title: Text(_AptNameList[index]),
value: _isAptChecked[index],
onChanged: (value) {
setState(() { // SetState in FutureBuilder
_isAptChecked[index] = value;
});
},
);
},
),
);
}
}
});
}
下拉代码
Widget Dropdown(int nDepth, ArgumentClass ReceiveArgs,
List<List<String>> ListOfDepthList) {
String _Value = "";
List<DropdownMenuItem<String>> _itemList = null;
if (ListOfDepthList.length <= nDepth) {
_Value = "";
_itemList = null;
} else {
_Value = _SelectedAddressList[nDepth];
_itemList = GetMainItem(ListOfDepthList[nDepth]);
}
return DropdownButton(
value: _Value,
items: _itemList,
onChanged: (value) {
if (value.compareTo(GlobalObject().startMessage) != 0) {
setState(() {
.....
// setState in Dropdown
});
}
});
}
请阅读FutureBuilder documentation。它指出:
The future must have been obtained earlier, e.g. during
State.initState, State.didUpdateWidget, or
State.didChangeDependencies. It must not be created during the
State.build or StatelessWidget.build method call when constructing the
FutureBuilder. If the future is created at the same time as the
FutureBuilder, then every time the FutureBuilder's parent is rebuilt,
the asynchronous task will be restarted.
如文档所述,获取 initState
中的未来并将其存储在您的状态中。
Future future;
@override
void initState() {
future = AptNameListView(widget.ReceiveArgs);
super.initState();
}
Widget AptListview() {
return FutureBuilder<List<String>>(
future: future,
builder: (context, snapshot) {
if (_bLastDepth == false) {
return Text("Select Address");
} else {
if (snapshot.hasData == false || snapshot.data.isEmpty == true) {
return CircularProgressIndicator();
} else {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: _AptNameList.length,
itemBuilder: (context, index) {
//return new Text("${_AptName[index]}");
return CheckboxListTile(
title: Text(_AptNameList[index]),
value: _isAptChecked[index],
onChanged: (value) {
setState(() { // SetState in FutureBuilder
_isAptChecked[index] = value;
});
},
);
},
),
);
}
}
});
}
我通过
解决了这个问题
- 在 dropbox 的 setState 中调用 future 函数
- 将 Futurebuilder 更改为 Listview。
当调用 SetState 时,它阻止了 futurebuilder 中列表视图的更新。
我正在制作一个页面,其中包含一些相互交互的保管箱和一个 Futurebuilder 包装的 ListView。
我正在调用 'setState',当 Dropbox 发生变化并且复选框被点击时。 但是因为checkbox的onChanged中的setState,Futurebuilder一直被调用,ListView被重建。 因此,当像下面的视频一样单击复选框时,整个 Listview 都会闪烁。
我想保留 Listview and update only 复选框。 有没有人可以帮助我? 谢谢。
完整代码为
class _StatefulDialogWidgetState extends State<StatefulDialogWidget> {
....
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Dropdown's
Dropdown(0, widget.ReceiveArgs, _lListOfDepthList),
Dropdown(1, widget.ReceiveArgs, _lListOfDepthList),
Dropdown(2, widget.ReceiveArgs, _lListOfDepthList),
Dropdown(3, widget.ReceiveArgs, _lListOfDepthList),
Dropdown(4, widget.ReceiveArgs, _lListOfDepthList),
// Listview with FutureBuilder
AptListview(),
],
);
}
列表视图代码
Widget AptListview() {
return FutureBuilder<List<String>>(
future: AptNameListView(widget.ReceiveArgs),
builder: (context, snapshot) {
if (_bLastDepth == false) {
return Text("Select Address");
} else {
if (snapshot.hasData == false || snapshot.data.isEmpty == true) {
return CircularProgressIndicator();
} else {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: _AptNameList.length,
itemBuilder: (context, index) {
//return new Text("${_AptName[index]}");
return CheckboxListTile(
title: Text(_AptNameList[index]),
value: _isAptChecked[index],
onChanged: (value) {
setState(() { // SetState in FutureBuilder
_isAptChecked[index] = value;
});
},
);
},
),
);
}
}
});
}
下拉代码
Widget Dropdown(int nDepth, ArgumentClass ReceiveArgs,
List<List<String>> ListOfDepthList) {
String _Value = "";
List<DropdownMenuItem<String>> _itemList = null;
if (ListOfDepthList.length <= nDepth) {
_Value = "";
_itemList = null;
} else {
_Value = _SelectedAddressList[nDepth];
_itemList = GetMainItem(ListOfDepthList[nDepth]);
}
return DropdownButton(
value: _Value,
items: _itemList,
onChanged: (value) {
if (value.compareTo(GlobalObject().startMessage) != 0) {
setState(() {
.....
// setState in Dropdown
});
}
});
}
请阅读FutureBuilder documentation。它指出:
The future must have been obtained earlier, e.g. during State.initState, State.didUpdateWidget, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.
如文档所述,获取 initState
中的未来并将其存储在您的状态中。
Future future;
@override
void initState() {
future = AptNameListView(widget.ReceiveArgs);
super.initState();
}
Widget AptListview() {
return FutureBuilder<List<String>>(
future: future,
builder: (context, snapshot) {
if (_bLastDepth == false) {
return Text("Select Address");
} else {
if (snapshot.hasData == false || snapshot.data.isEmpty == true) {
return CircularProgressIndicator();
} else {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: _AptNameList.length,
itemBuilder: (context, index) {
//return new Text("${_AptName[index]}");
return CheckboxListTile(
title: Text(_AptNameList[index]),
value: _isAptChecked[index],
onChanged: (value) {
setState(() { // SetState in FutureBuilder
_isAptChecked[index] = value;
});
},
);
},
),
);
}
}
});
}
我通过
解决了这个问题- 在 dropbox 的 setState 中调用 future 函数
- 将 Futurebuilder 更改为 Listview。
当调用 SetState 时,它阻止了 futurebuilder 中列表视图的更新。