Dart 从列表中删除项目后更新UI
如果删除或添加项目,我想更新我的ListView。现在我只想删除项目,并立即看到项目的删除 我的应用程序更复杂,所以我写了一个小的示例项目来说明我的问题Dart 从列表中删除项目后更新UI,dart,flutter,Dart,Flutter,如果删除或添加项目,我想更新我的ListView。现在我只想删除项目,并立即看到项目的删除 我的应用程序更复杂,所以我写了一个小的示例项目来说明我的问题 TestItem类包含一些数据项: class TestItem { static int id = 1; bool isFinished = false; String text; TestItem() { text = "Item ${id++}"; } } ItemInfoViewWidget是TestIte
TestItem
类包含一些数据项:
class TestItem {
static int id = 1;
bool isFinished = false;
String text;
TestItem() {
text = "Item ${id++}";
}
}
ItemInfoViewWidget
是TestItem
的UI表示,如果该项已完成(只要复选框更改为true),则会删除该项
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)),
);
}
}
void main()=>runApp(新的MyApp());
类MyApp扩展了无状态小部件{
//此小部件是应用程序的根。
@凌驾
小部件构建(构建上下文){
返回新材料PP(
标题:“颤振演示”,
主题:新主题数据(
主样本:颜色。蓝色,
),
主页:新MyHomePage(标题:“颤振演示主页”),
);
}
}
类MyHomePage扩展StatefulWidget{
MyHomePage({Key,this.title}):超级(Key:Key);
最后的字符串标题;
@凌驾
_MyHomePageState createState()=>new_MyHomePageState();
}
类_MyHomePageState扩展状态{
int _计数器=0;
列表项=新列表();
_MyHomePageState(){
对于(int i=0;i<20;i++){
this.items.add(new TestItem());
}
}
@凌驾
小部件构建(构建上下文){
归还新脚手架(
appBar:新的appBar(
标题:新文本(widget.title),
),
正文:新栏目(
儿童:[
ItemInfoViewWidget(this.items,this.items.first),
扁平按钮(
子项:新文本(“打开详细视图”),
按下:按钮已按下,
)
],
));
}
void按钮单击(){
导航器。推(
上下文
MaterialPage路由(生成器:(上下文)=>ItemViewWidget(this.items)),
);
}
}
如果我切换第一个项目的复选框,复选框将标记为已完成(如预期),但它不会从UI中删除,而是从列表中删除
然后我回到主页,我可以看到第1项也被选中了
因此,如果我再次转到ItemViewWidget
页面,我可以观察到选中的项目不再存在。
根据这些观察,我得出结论,我的实现是可行的,但我的UI没有更新
如何更改代码以立即更新UI
编辑:这不是重复的,因为
this.items=List.from(this.items)代码>但我的应用程序的行为与上面描述的相同
List.from
来破坏我的引用链,因为我的体系结构有一个列表,它被几个类引用。如果我打破了这个链条,我必须自己更新所有的参考资料。我的架构有问题吗李>
我不想仅仅为了更新UI而创建列表的新实例
颤振使用不可变对象。不遵守这一规则将违反被动框架。这是减少bug的自愿要求
事实上,这种不变性在这里特别是为了阻止开发人员做您目前正在做的事情:拥有一个依赖于在类之间共享同一对象实例的程序;因为多个类可能需要修改它
真正的问题在于,正是列表项从列表中删除了一个元素 问题是,由于是您的项目进行计算,因此不会通知家长列表已更改。因此它不知道应该重新播放。所以视觉上没有什么变化 要解决这个问题,您应该将删除逻辑移到父级。并确保父级相应地正确调用
setState
。这将转化为向列表项传递回调,删除时将调用该回调
下面是一个例子:
class MyList extends StatefulWidget {
@override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyList> {
List<String> list = List.generate(100, (i) => i.toString());
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return MyItem(list[index], onDelete: () => removeItem(index));
},
);
}
void removeItem(int index) {
setState(() {
list = List.from(list)
..removeAt(index);
});
}
}
class MyItem extends StatelessWidget {
final String title;
final VoidCallback onDelete;
MyItem(this.title, {this.onDelete});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(this.title),
onTap: this.onDelete,
);
}
}
class MyList扩展了StatefulWidget{
@凌驾
_MyListState createState();
}
类_MyListState扩展状态{
List=List.generate(100,(i)=>i.toString());
@凌驾
小部件构建(构建上下文){
返回ListView.builder(
itemCount:list.length,
itemBuilder:(上下文,索引){
返回MyItem(列表[索引],onDelete:()=>removeItem(索引));
},
);
}
void removietem(int索引){
设置状态(){
列表=列表。从(列表)
..移除(索引);
});
}
}
类MyItem扩展了无状态小部件{
最后的字符串标题;
最终删除;
MyItem(this.title,{this.onDelete});
@凌驾
小部件构建(构建上下文){
返回列表块(
标题:文本(此标题),
onTap:this.onDelete,
);
}
}
可能重复@RémiRousselet我遵循了答案,但我的解决方案没有什么不同。该项已删除,但未在UI中更新。我也不想创建新列表,因为ItemViewWidget中的列表与MyApp列表“断开”连接。也可能是因为我的架构不好,有更好的方法来完成我想要做的事情?您的列表实例保持不变。你不应该调用list.remove
。为什么我不应该调用list.remove?我用调试器查看了我的代码,比较了List.from前后实例的哈希代码。之前是623876470,之后是812698102。我猜List.from会创建一个新实例(或者hashcode不是跟踪实例的正确指标)。您应该故意创建一个新实例,从而创建列表。从
中,我评估了您的解决方案,它正在按原样工作。然而,我很高兴
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)),
);
}
}
class MyList extends StatefulWidget {
@override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyList> {
List<String> list = List.generate(100, (i) => i.toString());
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return MyItem(list[index], onDelete: () => removeItem(index));
},
);
}
void removeItem(int index) {
setState(() {
list = List.from(list)
..removeAt(index);
});
}
}
class MyItem extends StatelessWidget {
final String title;
final VoidCallback onDelete;
MyItem(this.title, {this.onDelete});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(this.title),
onTap: this.onDelete,
);
}
}