[英]How to remove a widget from the screen without rebuilding the whole page in flutter
[英]How to change ListTile data with mobx without rebuilding the whole page #Flutter
我正在使用 mobx 學習 Flutter state 管理,並且我想在不重建整個頁面的情況下更改動態 listtile 的上下文,我嘗試了從 Mobx 商店獲取的可觀察列表,但我的示例在這里似乎不起作用。
此示例我想單擊名稱更改為單擊而不重建屏幕的項目,當我單擊時沒有任何反應,但是當我 go 返回另一個頁面並返回時,我發現動物的名稱已更改。
這是我的無狀態小部件
Class AnimalPageList extends StatelessWidget{
@override
Widget build(BuildContext context){
var animalStore = context.watch<AnimalStore>();
var animals = animalStore.animalsList;
return Scaffold(
appBar: AppBar(
title: Text("Animals Page"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Observer(builder: (_) =>
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: animals.length,
itemBuilder: (BuildContext context, int index) {
var pet = animalStore.getAnimal(index);
//final petName = context.select((ObservableList<Animal> animals)=>animals[index].name);
return ListTile(
key: ValueKey(pet.id),
enabled: true,
onTap: () async {
var rename = animals[index].name +" clicked";
animals[index].name = rename;
},
title: Observer(builder: (_) => Text(pet.name)),
);
},
),
),
],
),
),
);
這是我的 model 與商店
class Animal {
final int id;
@observable
String name;
Animal({this.id, this.name});
factory Animal.fromJson(Map<dynamic, dynamic> json) {
return new Animal(
id: json['id'],
name: json['name'],
);
}
Map<dynamic, dynamic> toJson() {
final Map<dynamic, dynamic> data = new Map<dynamic, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}
class AnimalStore = _AnimalStore with _$AnimalStore;
abstract class _AnimalStore with Store{
@observable
ObservableList animalsList = ObservableList<Animal>.of(
[
Animal(id: 1, name: 'cat'),
Animal(id: 2, name: 'dog'),
Animal(id: 3, name: 'mouse'),
Animal(id: 4, name: 'horse'),
Animal(id: 5, name: 'frog'),
]
);
@action
getAnimal(int i){
return animalsList[i];
}
}
我可以安排哪種方式,model,商店和sreenwidget,這樣如果我點擊一個按鈕,它會根據需要更改名稱,而無需重建整個屏幕。
從您的代碼看來,列表大小是 static 並且它不會隨着時間而改變,基於這個事實,您可以 go 獲得一個簡單的解決方案,如下所示:
首先,您正在觀察整個列表,以及其中的 Text 小部件,此處過度設計。
只需將 Observer 包裹在ListTile周圍,這樣只有特定的ListTile會在更新到其觀察到的 var 時重建。 使用UniqueKey()作為每個元素的鍵。
此外,您需要引用 Observer 中的vars存儲。 您可以在任何地方調用存儲操作,而無需在Observer小部件中。
您需要創建一個操作方法來更新動物的名稱。
提示:避免在循環或僅用於臨時保留的列表中創建新變量,構建器內的“變量重命名”不是一個好習慣。
通常我會創建一個代表商店的 object 的全局實例,並且可以被項目中的任何小部件/文件重用。
AnimalStore animalStore = AnimalStore();
代碼應修改如下:
//_AnimalStore class
@action
setAnimalName(int i, string name){
animalsList[i].name = name;
}
//AnimalPageList class
Class AnimalPageList extends StatelessWidget{
@override
Widget build(BuildContext context){
// you dont realy need them
var animalStore = context.watch<AnimalStore>();
var animals = animalStore.animalsList;
return Scaffold(
appBar: AppBar(
title: Text("Animals Page"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: animalStore.animalsList.length,
itemBuilder: (BuildContext context, int index) {
return Observer(builder: (_) => ListTile(
key: ValueKey(pet.id),
enabled: true,
onTap: () {
animalStore.setAnimalName(index, animalStore.getAnimal(index).name +" clicked");
},
title: Text(animalStore.getAnimal(index)),
));
},
),
],
),
),
);
首先,我認為@fpatelm 已經以不同的方式告訴了我要說的一切。 只是以不同的方式添加幾乎相同的解釋,以使事情更清楚。
更改 ObservableList 中元素的值不會更新屏幕,除非 ObservableList 中的每個個體也是 Observable。 沒有 Observables 作為元素的 Observable 列表只會在改變其大小(ObservableList.length)時發生變化。
解決此問題的一種方法是在更改任何元素時重建 Observable 列表。
@action
void onEditElement(Animal obj){
final elemIndex = animalsList.findElementIndex(obj);
final aux = ObservableList<Animal>.of([]);
aux.copyAll(animalsList);
aux[elemIndex] = obj;
a.nimalsList = aux;
}
其次,您正在 {} 中克隆存儲,這意味着您與存儲在不同的 scope 中,不完全確定這是否是一個問題,但在我看來。
嘗試創建自定義磁貼,接收存儲值並返回 ListTile:
CustomTile extends StatelessWidget{
const CustomTile(Animal pet);
Builder{
return ListTile(key: UniqueKey(), title: pet.name, ...,);
}
}
itemBuilder: (BuildContext context, int index) {
return CustomTile(
animalStore.getAnimal(index),
);
}
如果不能解決問題,請嘗試添加密鑰:UniqueKey(); 而不是 pet.id。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.