【发布时间】:2019-01-26 14:23:15
【问题描述】:
如果我删除或添加项目,我想更新我的 ListView。现在我只想删除项目并立即查看项目的删除。
我的应用程序更复杂,所以我写了一个小示例项目来展示我的问题。
TestItem 类包含一些数据条目:
class TestItem {
static int id = 1;
bool isFinished = false;
String text;
TestItem() {
text = "Item ${id++}";
}
}
ItemInfoViewWidget 是 TestItem 的 UI 表示形式,如果项目完成(只要复选框更改为 true),就会删除项目。
class ItemInfoViewWidget extends StatefulWidget {
TestItem item;
List<TestItem> items;
ItemInfoViewWidget(this.items, this.item);
@override
_ItemInfoViewWidgetState createState() =>
_ItemInfoViewWidgetState(this.items, this.item);
}
class _ItemInfoViewWidgetState extends State<ItemInfoViewWidget> {
TestItem item;
List<TestItem> items;
_ItemInfoViewWidgetState(this.items, this.item);
@override
Widget build(BuildContext context) {
return new Card(
child: new Column(
children: <Widget>[
new Text(this.item.text),
new Checkbox(
value: this.item.isFinished, onChanged: isFinishedChanged)
],
),
);
}
void isFinishedChanged(bool value) {
setState(() {
this.item.isFinished = value;
this.items.remove(this.item);
});
}
}
ItemViewWidget 类构建 ListView。
class ItemViewWidget extends StatefulWidget {
List<TestItem> items;
ItemViewWidget(this.items);
@override
_ItemViewWidgetState createState() => _ItemViewWidgetState(this.items);
}
class _ItemViewWidgetState extends State<ItemViewWidget> {
List<TestItem> items;
_ItemViewWidgetState(this.items);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: new Text('Test'),
),
body: ListView.builder(
itemCount: this.items.length,
itemBuilder: (BuildContext context, int index) {
return new ItemInfoViewWidget(this.items, this.items[index]);
}),
);
}
}
MyApp 显示一个TestItem 和一个导航到ItemViewWidget 页面的按钮。
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
List<TestItem> items = new List<TestItem>();
_MyHomePageState() {
for (int i = 0; i < 20; i++) {
this.items.add(new TestItem());
}
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Column(
children: <Widget>[
ItemInfoViewWidget(this.items, this.items.first),
FlatButton(
child: new Text('Open Detailed View'),
onPressed: buttonClicked,
)
],
));
}
void buttonClicked() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ItemViewWidget(this.items)),
);
}
}
如果我切换第一个项目的复选框,复选框被标记为已完成(如预期的那样),但它不会从 UI 中删除 - 但是它会从列表中删除。
然后我回到主页,我可以观察到项目 1 也在那里被选中。
所以如果我再次访问ItemViewWidget 页面,我可以观察到已检查的项目不再存在。
根据这些观察,我得出的结论是我的实现有效,但我的 UI 没有更新。
如何更改我的代码以使 UI 立即更新成为可能?
编辑:这不是重复的,因为
- 我不想为了更新 UI 而创建列表的新实例。
- 答案无效:我添加了
this.items = List.from(this.items);,但我的应用程序的行为与上面已经描述的相同。 - 我不想通过调用
List.from来破坏我的引用链,因为我的架构有一个被多个类引用的列表。如果我打破链条,我必须自己更新所有参考资料。我的架构有问题吗?
【问题讨论】:
-
@RémiRousselet 我遵循了答案,但我的解决方案没有任何区别。该项目已删除,但未在 UI 中更新。我也不想创建一个新列表,因为那时我在 ItemViewWidget 中的列表与 MyApp 列表“断开连接”。也可能是我的架构不好,有更好的方法来完成我想做的事情吗?
-
您的列表实例保持不变。你不应该打电话给
list.remove。 -
为什么我不能调用 list.remove?我用调试器查看了我的代码,并比较了 List.from 前后实例的哈希码。之前是 623876470,之后是 812698102。我猜 List.from 创建了一个新实例(或者哈希码不是跟踪实例的正确指标)。
-
就是这样。您应该故意创建一个新实例,因此
List.from