我下面有这样的代码,简单的流程是我从对象列表中进行循环以创建一些小部件。
class ScoringAttribute {
int _id;
bool _isdelete;
double _scorehigh, _scorelow, _scorevalue;
String _name, _scoretype, _description, _title;
}
class HomePageState extends State<HomePage> with TickerProviderStateMixin {
List dataScoringAttributes;
List<ScoringAttribute> listScoringAttributeObjects = new List<ScoringAttribute>();
final String urlPresentation = ".../.resentations/getPresentations";
final String urlScoringAttribute = ".../.scoringattributes/getScoringattributes";
Future<String> getPresentationData() async {
var responseScoringAttribute = await http.get(
Uri.encodeFull(urlScoringAttribute),
headers: {"Accept": "application/json"}
);
var scoringAttributeJson = json.decode(responseScoringAttribute.body);
dataScoringAttributes = scoringAttributeJson['scoringattributes'];
for(int i = 0; i < dataScoringAttributes.length; i++) {
var scoringAttributeObject = new ScoringAttribute();
scoringAttributeObject._id = dataScoringAttributes[i]["id"];
scoringAttributeObject._description = dataScoringAttributes[i]["iddescription"];
scoringAttributeObject._isdelete = dataScoringAttributes[i]["isdelete"];
scoringAttributeObject._name = dataScoringAttributes[i]["name"];
scoringAttributeObject._scorehigh = double.parse(dataScoringAttributes[i]["scorehigh"].toString());
scoringAttributeObject._scorelow = double.parse(dataScoringAttributes[i]["scorelow"].toString());
scoringAttributeObject._scoretype = dataScoringAttributes[i]["scoretype"];
scoringAttributeObject._title = dataScoringAttributes[i]["title"];
scoringAttributeObject._scorevalue = double.parse(dataScoringAttributes[i]["scorelow"].toString());
listScoringAttributeObjects.add(scoringAttributeObject);
}
return "Success";
}
List<Widget> scoringAttributeList() {
List<Widget> list = new List();
for(int i = 0; i < listScoringAttributeObjects.length; i++) {
if(listScoringAttributeObjects[i]._scoretype == "slider") {
list.add(
new Container(
child: new Column(
children: <Widget>[
new Column(
children: <Widget>[
//THE SLIDER VALUE TEXT
new Text(
//CONVERT DOUBLE TYPE TO STRING WITHOUT DECIMAL POINTS
listScoringAttributeObjects[i]._scorevalue.toStringAsFixed(listScoringAttributeObjects[i]._scorevalue.truncateToDouble() == listScoringAttributeObjects[i]._scorevalue ? 0 : 0),
style: new TextStyle(
fontSize: 28.0,
),
),
//THE SLIDER
new Slider(
activeColor: Colors.blueAccent,
inactiveColor: const Color(0xFFb7d2e0),
min: double.parse(listScoringAttributeObjects[i]._scorelow.toString()),
max: double.parse(listScoringAttributeObjects[i]._scorehigh.toString()),
value: double.parse(listScoringAttributeObjects[i]._scorevalue.toString()),
onChanged: (double value) {
setState(() {
listScoringAttributeObjects[i]._scorevalue = double.parse(value.round().toString());
});
},
),
],
),
],
),
),
);
}
else if(listScoringAttributeObjects[i]._scoretype == "text_field") {
list.add(...);
}
else if(listScoringAttributeObjects[i]._scoretype == "stars") {
list.add(...);
}
else if(listScoringAttributeObjects[i]._scoretype == "thumb") {
list.add(new Container(...);
}
}
return list;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: FutureBuilder<String> (
future: getPresentationData(),
builder: (context, snapshot) {
if(snapshot.hasData) {
return new Column(
children: <Widget>[
new Column(
children: scoringAttributeList(),
),
],
),
}
},
),
);
}
}
取决于类型,有一些不同的窗口小部件,并且有4种类型,其中1种类型可能包含1个以上的窗口小部件,因此我使循环取决于iIgot从数据库获取的数据。
问题是我不知道为什么每次在循环中使用setState()
时,它总是再次处理该循环,因此创建新的小部件将是一个无限循环,并且将复制窗口小部件(仅在调用setState()时发生)。
例如:列表中有4个数据,如果调用setState()
,它将显示8个数据(显示前4个数据两次)
这是示例如何将State()设置到列表中的数据中的例子
onChanged: (double value) {
setState(() {
listScoringAttributeObjects[i]._scorevalue = double.parse(value.round().toString());
});
},
我认为问题是因为我setState()
进入了列表内的一些数据。因此,当List状态更改时,它将重新呈现与List相关的任何内容。
是真的吗?
如果是,还有其他解决方案如何更改我的代码? 如果没有,那么我的代码或逻辑中是否有任何错误?
谢谢。真的很期待有关此问题的解决方案,因为我确实陷入了困境,并且已经过去了一个星期:(
答案 0 :(得分:0)
我看不出这与您代码中的一个setState()
有什么关系。仅在使用滑块时才调用它。
我认为问题是由list.add(...)引起的;在scoringAttributeList()中。在执行build()时,您不应修改数据。
您应该假设build()
可以随时被重复调用。
构建您的代码,以使其在发生时不会引起问题。
答案 1 :(得分:0)
只需将getPresentationData()
移到状态变量。这样它只会一次获得triggered
。
class HomePageState extends State<HomePage> with TickerProviderStateMixin {
Future<String> _presentationFuture;
initState() {
_presentationFuture = getPresentationData()
}
//other contents
@override
Widget build(BuildContext context) {
return new Scaffold(
body: FutureBuilder<String> (
future: _presentationFuture,
builder: (context, snapshot) {
if(snapshot.hasData) {
重复的原因:我们可以在Slider dataChange上调用setState
,它将重新呈现HomePageState
,这将再次触发network
调用({{ 1}})
注意:如果要在更改滑块时触发网络,请在拨打网络电话之前清除列表
getPresentationData()