flutter - Flutter Provider:如何通知模型它包含的模型发生了变化?
问题描述
我开始通过使用 Provider 构建一个简单的 Todo 应用程序来学习 Flutter/Dart,但我遇到了一个状态管理问题。需要明确的是,我编写的代码有效,但似乎......错了。我找不到任何与我的案例相似的例子,足以让我理解解决问题的正确方法是什么。
这是一个按部分(“冷冻”、“水果和蔬菜”)划分的杂货清单。每个部分都有多个项目,并显示“已完成 x of y”进度指示器。每个项目在按下时都会“完成”。
GroceryItemModel
看起来像这样:
class GroceryItemModel extends ChangeNotifier {
final String name;
bool _completed = false;
GroceryItemModel(this.name);
bool get completed => _completed;
void complete() {
_completed = true;
notifyListeners();
}
}
我在GroceryItem
小部件中使用它,如下所示:
class GroceryItem extends StatelessWidget {
final GroceryItemModel model;
GroceryItem(this.model);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: model,
child: Consumer<GroceryItemModel>(builder: (context, groceryItem, child) {
return ListTile(
title: Text(groceryItem.name),
leading: groceryItem.completed ? Icon(Icons.check_circle, color: Colors.green) : Icon(Icons.radio_button_unchecked)
onTap: () => groceryItem.complete();
})
);
}
}
我想要的下一步是在一个部分中包含多个项目,它根据完成的项目数量来跟踪完整性。
GroceryListSectionModel
看起来像这样:
class GroceryListSectionModel extends ChangeNotifier {
final String name;
List<GroceryItemModel> items;
GroceryListSectionModel(this.name, [items]) {
this.items = items == null ? [] : items;
// THIS RIGHT HERE IS WHERE IT GETS WEIRD
items.forEach((item) {
item.addListener(notifyListeners);
});
// END WEIRD
}
int itemCount() => items.length;
int completedItemCount() => items.where((item) => item.completed).length;
}
我在GroceryListSection
小部件中使用它,如下所示:
class GroceryListSection extends StatelessWidget {
final GroceryListSectionModel model;
final ValueChanged<bool> onChanged;
GroceryListSection(this.model, this.onChanged);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: model,
child: Consumer<GroceryListSectionModel>(
builder: (context, groceryListSection, child) {
return Container(
child: ExpansionTile(
title: Text(model.name),
subtitle: Text("${groceryListSection.completedItemCount()} of ${groceryListSection.itemCount()} completed"),
children: groceryListSection.items.map((groceryItemModel) =>
GroceryItem(groceryItemModel)).toList()
)
);
}
)
);
}
}
问题:
ChangeNotifierProvider
在两个小部件中都有 a和 a似乎很奇怪Consumer
。我见过的例子都没有做到这一点。- 监听所有更改以传播到树上绝对是错误的。我看不出它如何正确扩展。
GroceryListSectionModel
GroceryItemModels
有什么建议么?谢谢!
解决方案
这不是嵌套提供程序,但我认为在您的示例中这是更好的方法..
每个section ("Frozen", "Fruits and Veggies")
仅定义一个 ChangeNotifierProvider
complete()
来自 a的函数ItemModel
在GroceryListSectionModel()
and 中,带有来自当前列表索引的参数
class GroceryListSection extends StatelessWidget {
final GroceryListSectionModel model;
// final ValueChanged<bool> onChanged;
GroceryListSection(this.model);
@override
Widget build(BuildContext context) {
return new ChangeNotifierProvider<GroceryListSectionModel>(
create: (context) => GroceryListSectionModel(model.name, model.items),
child: new Consumer<GroceryListSectionModel>(
builder: (context, groceryListSection, child) {
return Container(
child: ExpansionTile(
title: Text(model.name),
subtitle: Text("${groceryListSection.completedItemCount()} of ${groceryListSection.itemCount()} completed"),
children: groceryListSection.items.asMap().map((i, groceryItemModel) => MapEntry(i, GroceryItem(groceryItemModel, i))).values.toList()
)
);
}
)
);
}
}
class GroceryItem extends StatelessWidget {
final GroceryItemModel model;
final int index;
GroceryItem(this.model, this.index);
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(model.name),
leading: model.completed ? Icon(Icons.check_circle, color: Colors.green) : Icon(Icons.radio_button_unchecked),
onTap: () => Provider.of<GroceryListSectionModel>(context, listen: false).complete(index),
);
}
}
class GroceryListSectionModel extends ChangeNotifier {
String name;
List<GroceryItemModel> items;
GroceryListSectionModel(this.name, [items]) {
this.items = items == null ? [] : items;
}
int itemCount() => items.length;
int completedItemCount() => items.where((item) => item.completed).length;
// complete Void with index from List items
void complete(int index) {
this.items[index].completed = true;
notifyListeners();
}
}
// normal Model without ChangeNotifier
class GroceryItemModel {
final String name;
bool completed = false;
GroceryItemModel({this.name, completed}) {
this.completed = completed == null ? false : completed;
}
}
推荐阅读
- python - 取消用户窗口大小
- python - 当我执行它时,为什么我的童年没有参数但是当我在字符串 q 中删除学校时,它会出现 NameError
- visual-studio-code - 由于 vscode 的 sudo apt update 警告
- flutter - 为什么颤振本地化不能正常工作?
- powerbi - SSAS - 导入时的多维数据集过滤
- javascript - 如何使用 Bootstrap 4 和 JavaScript 将“$”保留在输入字段的占位符内
- ruby-on-rails - 使用捆绑安装时出错:nokogiri 安装错误
- python - 在 pycharm 中如何在此对话框中将单元测试更改为 pytest
- python - 更改日期格式将 mmm-yy 转换为 yyyy/mm/dd
- c# - 如何通过将实体转换为 DTO 来实现 Linq 查询?