我是使用Flutter / Dart的新手,我很难理解为什么_updateResults()调用setState()时,以下代码为什么不更新ListView内容。我什至添加了一条打印语句来显示_results
的内容,并且可以看到项目已添加到列表中,但显示从未更新。
class SearchHomePage extends StatefulWidget {
SearchHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
createState() => _SearchHomePageState();
}
class _SearchHomePageState extends State<SearchHomePage> {
List<Widget> _results = <Widget>[];
@override
void initState() {
super.initState();
_results.add(Text("testing"));
}
void _updateResults(String text) {
setState(() {
_results.add(Text(text));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(children: [
Container(
child: TextField(
onSubmitted: (String text) {
_updateResults(text);
},
),
),
Expanded(
child: ListView(children: _results)
),
]),
);
}
}
如果我将ListView部分更改为:
Expanded(
child: ListView(children: _results.toList())
)
然后它将起作用,我不确定为什么,因为它已经是列表。到底发生了什么,为什么它不能仅与ListView一起使用?
答案 0 :(得分:0)
它不起作用,因为您是将新项目添加到现有列表中,而不是创建新列表。
这将解决您的问题:
class SearchHomePage extends StatefulWidget {
SearchHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
createState() => _SearchHomePageState();
}
class _SearchHomePageState extends State<SearchHomePage> {
List<Widget> _results = <Widget>[];
@override
void initState() {
super.initState();
_results.add(Text("testing"));
}
void _updateResults(String text) {
setState(() {
_results = [..._results, Text(text)];
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(children: [
Container(
child: TextField(
onSubmitted: (String text) {
_updateResults(text);
},
),
),
Expanded(
child: ListView(children: _results)
),
]),
);
}
}
注意:最好做以下事情,而不是创建小部件并将它们保存在数组中:
class SearchHomePage extends StatefulWidget {
SearchHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
createState() => _SearchHomePageState();
}
class _SearchHomePageState extends State<SearchHomePage> {
List<String> _results = <String>[];
@override
void initState() {
super.initState();
_results.add("testing");
}
void _updateResults(String text) {
setState(() {
_results = [..._results, text];
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(children: [
Container(
child: TextField(
onSubmitted: (String text) {
_updateResults(text);
},
),
),
Expanded(
child: ListView(
children: _results.map((v) => Text(v)).toList(),
)),
]),
);
}
}
调用.toList()时,它将创建一个新的列表实例(旧列表的副本)
答案 1 :(得分:0)
ListView(
shrinkWrap: true,
children: _results.map((one) => one).toList(),
),
ListView.builder(
shrinkWrap: true,
itemCount: _results.length,
itemBuilder: (context, index) => _results[index],
),
如果您努力根据自己的要求获得输出,则必须像上面对以下代码的理解那样更改代码:
Expanded(
child: ListView(children: _results.toList()))
请同时放置两个列表中的任何一个...
答案 2 :(得分:0)
来自StatefulWidget documentation:
StatefulWidget实例本身是不可变的,并将其可变状态存储在由createState方法创建的单独的State对象中,或存储在该State所预订的对象中。[...]
摘自this文章:
从定义上说,不可变是指一旦创建,就不能更改对象/变量。因此,不必更改对象的属性,而必须复制(或克隆)整个对象,然后在此过程中更改相关属性。
您使用相同的数组创建了ListView。您更改了数组的内容,但没有更改对该对象的引用。
这就是为什么当您使用_results.toList()
时它起作用的原因,因为.toList()
“创建了一个包含此[Iterable]元素的[List]”。
另一个解决方案可能是:
setState(() {
_results = List.from(_results)
..add(Text(text));
});