这篇文章来自于我自己的有道云笔记 想看图片去那里
文档:Day 4_8 项目实战以及 国际化.md
链接:http://note.youdao.com/noteshare?id=9a784492b39cbcd20f152885d183c884&sub=2193AB9CCC944AEAA4EA1EC8B8A0BB03
点击左边 然后刷新右边的数据 就是 如何进行组件间的信息传递
我们可以用 事件总线来完成 这个事件的传递
也可以使用Provider完成这个操作
因为这个数据 只有一边会使用 另外一边只是改动
所以我们使用事件总线会好一点
虽然我们的项目比较小 但是我们的东西 是比较全的
我们的Drawer我们发现它其实是因该将这个 tabbar给覆盖上的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YvE62le6-1589850162076)(E6CF70B0B0884D22A327D13910BC0BEC)]
其实也是能做的
之前我们做的时候是将Drawer放在HomeScreen里面的
我们的HomeScreen是只有 中间的部分
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4zOA4gMv-1589850162083)(2D133EFCF4BC4726B1DBBF32B8EA413E)]
所以是只能控制上面的部分
所以如果你想让 下面的部分也盖上的话 我们就需要将这个Drawer把上面的也盖上
我们就需要将Drawer也放到main里面
我们来到这个Drawer里面将 这个放到里面来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1RI9CQIy-1589850162087)(4D3DEE95DF3F4FDDB29B9FB7686C7ED4)]
那我们怎么把这个窗口弹出呢
我们其实点击这个HomeScreen的appBar的leading来将这个 弹出的
这个leading是属于 这个HomeScreen 那我们怎么来做呢
我们 来到这个home_app_bar.dart
import "package:flutter/material.dart";
class HYHomeAppBar extends AppBar {
HYHomeAppBar(BuildContext context):super(
title: Text("美食广场"),
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: Icon(Icons.build),
onPressed: () {
// 它这里的目的是为了拿到这个 Scaffold 然后调用它的一个openDrawer
// 这样来做的
Scaffold.of(context).openDrawer();
},
);
}
),
);
}
以前我们的做法是找到对应的Scaffold里面的Drawer 但是现在我们找的不是这里的Scaffold 而是要找外面的Scaffold 所以我们这里把这个 Builder给去掉就可以实现这个功能了
import "package:flutter/material.dart";
class HYHomeAppBar extends AppBar {
HYHomeAppBar(BuildContext context):super(
title: Text("美食广场"),
leading: IconButton(
icon: Icon(Icons.build),
onPressed: () {
// 它这里的目的是为了拿到这个 Scaffold 然后调用它的一个openDrawer
// 这样来做的
Scaffold.of(context).openDrawer();
},
)
);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RTyNX1lP-1589850162132)(7A6E74E53507469F956955B5AB1B52D3)]
这样我们就可以 弹出这个 Drawer了
我们只要去拿上一层的Scaffold就行了
然后就是 做一个过滤的页面
filter-> filter.dart
import "package:flutter/material.dart";
import 'package:project03/ui/pages/filter/filter_content.dart';
class HYFilterScreen extends StatelessWidget {
static const String routeName = "/filter";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("美食过滤"),
),
body: HYFilterContent(),
);
}
}
filter -> filter_content.dart
import "package:flutter/material.dart";
class HYFilterContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text("test");
}
}
然后就是在对应的位置弹出这个页面
home_drawer.dart
Widget build(BuildContext context) {
return Container(
width: 250.px,
child: Drawer(
child: Column(
children: [
buildHeaderView(context),
buildListTile(context, Icon(Icons.restaurant), "进餐", () {
Navigator.of(context).pop();
}),
buildListTile(context, Icon(Icons.settings), "过滤", () {
Navigator.of(context).pushNamed(routeName);
})
],
),
)
);
}
然后就是配置路由 但是如果这里我们配置路由的话
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hlemeWRD-1589850162134)(5B0EE73A6D2144C78E1BDD73159FF782)]
他的页面弹出方式就是从右往左 那如果你想自定义 来完成这个操作
我们可以在generateRoute来识别这个路由
// 自己扩展
static final RouteFactory generateRoute = (settings) {
if(settings.name == ) {
}
return null;
};
所以我们将这个识别以后包裹一个MaterialPageRoute
static final RouteFactory generateRoute = (settings) {
if(settings.name == HYFilterScreen.routeName) {
return MaterialPageRoute(
builder: (ctx) {
return HYFilterScreen();
},
fullscreenDialog: true
);
}
return null;
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SY5ljuCW-1589850162137)(7C4DD1BB8471485EB77CB04845E4667F)]
这样我们就能这样弹出页面了
我们来做这个看这个怎么做
上面的标题是固定死 然后这个是可以滚动的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lHBRoD6F-1589850162138)(9138A5EF4F8446519962683B894E20B2)]
import "package:flutter/material.dart";
import "../../../core/extension/int_extension.dart";
class HYFilterContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
buildYourChoice(context),
],
);
}
Widget buildYourChoice(BuildContext context) {
return Container(
padding: EdgeInsets.all(20.px),
alignment: Alignment.center,
child: Text("展示你的选择", style: Theme.of(context).textTheme.display3.copyWith(fontWeight: FontWeight.bold)),
);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kyNn76Uz-1589850162140)(356C37DEE94641ECA7F727A802789483)]
标题
ListView滚动区域
Widget buildChoiceSelect() {
return ListView(
children: [],
);
}
这个里面都是一些固定的内容 所以我们就不生成了
然后我们往里面放东西
但是这里是一定会报错的
Widget buildChoiceSelect() {
return ListView(
children: [
Text("aaa"),
Text("bbbb"),
Text("ccc"),
Text("aaa"),
Text("aaa"),
],
);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vd9TAHqt-1589850162141)(2532C6FCDF6741259F49E67998410839)]
又是这个hasSize同样我们的 父Widget需要子Widget穿过来大小 子Widget 它要站尽可能多的位置 所以这里就报错了
外面是一个Column里面有一个ListView 就出错了
那我们怎么办呢 我们给ListView设置一个包裹的属性 这样它就不会占据尽可能大的位置
Widget buildChoiceSelect() {
return ListView(
shrinkWrap: true,
children: [
Text("aaa"),
Text("bbbb"),
Text("ccc"),
Text("aaa"),
Text("aaa"),
],
);
}
但是这个东西 它一般用在 制作列表的时候
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iUtbQsMV-1589850162143)(A2FD36DEDFFF4F3EB3C5A4C66A0CE4EE)]
但是这里我们是希望占据 剩下的位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQBGmiUE-1589850162144)(7F97F7C7A3D44E80BA8EE73E0FAFCA65)]
这里就不要使用这种方案了 我们给它包裹一个Expend
我们给他 包裹一个Expanded
如果这个东西会将这个 内容延长到 剩余的空间 如果超过了就会压缩你的内容
Widget buildChoiceSelect() {
return Expanded(
child: ListView(
children: [
Text("aaa"),
Text("bbbb"),
Text("ccc"),
Text("aaa"),
Text("aaa"),
],
),
);
}
它会占据你垂直方向上的整个的空间
怎么证明呢
这里
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tLgKkKuQ-1589850162145)(D71366C762F84D5A9FD6FE0A0595BCC2)]
拖动的动画都延续到最下面了
我们肯定不是用这个Text
我们是用ListTile leading是放在前面的东西 traling就代表我尾部
Widget buildChoiceSelect() {
return Expanded(
child: ListView(
children: [
ListTile(
title: Text("五谷蛋白"),
subtitle: Text("五谷蛋白"),
trailing: Switch(
value: false,
onChanged: (value) {
},
),
)
],
),
);
}
但是这个东西因为会站很多地方会用 所以我们将这个东西封装一下
Widget buildChoiceSelect() {
return Expanded(
child: ListView(
children: [
buildListTile("五谷蛋白", "五谷蛋白", (value) {
}),
buildListTile("不含乳糖", "不含乳糖", (value) {
}),
buildListTile("素食主义", "素食主义", (value) {
}),
buildListTile("严格的素食主义", "严格的素食主义", (value) {
}),
],
),
);
}
Widget buildListTile(String title, String subtitle, Function onChange) {
return ListTile(
title: Text(title),
subtitle: Text(subtitle),
trailing: Switch(
value: false,
onChanged: onChange,
),
);
}
我们这个选中了以后 它就会过滤选中的如果 对应的属性没有
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6JXTHZ7s-1589850162146)(557D8741493F482883FE8448B06F8C34)]
这样就是 如果 你选中了不含乳糖 那么 这个选项就不会被过滤
我们到时候 选中对应的过滤的东西 我们首先要需要保存 这些bool类型的值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsq9y2BW-1589850162148)(FF36CFCC7B2148C19CC21E1751B1371A)]
而且他们还要 在不同的页面之前共享 所以我们就压把它放在Provider中
我们可以将这些数据 放到 MealViewModel一起保存
这样我们就只需要添加一些属性在 MealViewModel中即可 但是这里我们 数据 收藏地方也希望用到
这样的话我们的收藏就需要依赖这个Meal的Provider 其实也可以做
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cbYWQ0id-1589850162150)(26E5A30AC56044059AC30934577EB09D)]
这样来做它的耦合性就太高了 所以 这个bool值直接放到这里是不合适的
我们最好在搞一个FilterViewModel
让MealViewModel和FavorViewModel都依赖于这个FilterViewModel就可以了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61Taxu1S-1589850162152)(53C7C1AFECDF4CD88D639082F57F5054)]
MealViewModel和FavorViewModel 之间就没有依赖了
这样我们就可以
我们新建一个ViewModel.dart
然后 alt + insert 生成getter和setter
filter_view_model.dart
import 'package:flutter/material.dart';
class HYFilterViewModel extends ChangeNotifier {
// 五谷蛋白
bool _isGlutenFree = false;
// 素食主义
bool _isVegan = false;
// 严格的素食主义
bool _isVegetarian = false;
// 有无乳糖
bool _isLactoseFree = false;
bool get isGlutenFree => _isGlutenFree;
bool get isLactoseFree => _isLactoseFree;
bool get isVegetarian => _isVegetarian;
bool get isVegan => _isVegan;
set isGlutenFree(bool value) {
_isGlutenFree = value;
notifyListeners();
}
set isLactoseFree(bool value) {
_isLactoseFree = value;
notifyListeners();
}
set isVegetarian(bool value) {
_isVegetarian = value;
notifyListeners();
}
set isVegan(bool value) {
_isVegan = value;
notifyListeners();
}
}
这样我们就封装好了这个东西了
然后我们就需要在filter_content.dart里面使用
所以这里我们对他做操作
因为我们这里如果选择了 对应的按钮他因该是true的但是我们这里封装的 因该只有false
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kGZtxuWd-1589850162153)(0140C0EEBE7E4AADB9835118EE602BC1)]
我把这个东西给你产生对应的参数
传到里面来显示 同时在点击以后修改
filter_content.dart
Widget buildChoiceSelect() {
return Expanded(
child: Consumer(
builder: (ctx, filterVM, child) {
return ListView(
children: [
buildListTile("五谷蛋白", "五谷蛋白", filterVM.isGlutenFree, (value) {
filterVM.isGlutenFree = value;
}),
buildListTile("不含乳糖", "不含乳糖", filterVM.isLactoseFree, (value) {
filterVM.isLactoseFree = value;
}),
buildListTile("素食主义", "素食主义", filterVM.isVegan, (value) {
filterVM.isVegan = value;
}),
buildListTile("严格的素食主义", "严格的素食主义", filterVM.isVegetarian, (value) {
filterVM.isVegetarian = value;
}),
],
);
}
),
);
}
Widget buildListTile(String title, String subtitle, bool value, Function onChange) {
return ListTile(
title: Text(title),
subtitle: Text(subtitle),
trailing: Switch(
value: value,
onChanged: onChange,
),
);
}
同时要将这个Provider放到对应的依赖里面去
main.dart
void main() {
// Provider -> ViewModel / Provider / Consumer(Selector)
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => HYMealViewModel(),
),
ChangeNotifierProvider(
create: (ctx) => HYFavorViewModel(),
),
ChangeNotifierProvider(
create: (ctx) => HYFilterViewModel(),
)
],
child: MyApp(),
)
);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DnRYdE56-1589850162155)(8412533A44C5406B8C5C5EF9501A8B5A)]
这个时候我们就将这个内容在provider里面做了一个记录了
所以我们就需要用这个数据来对我们的数据来做一个过滤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vLcV29Sg-1589850162156)(9428155FA6DB45B5A391A2AC911C7818)]
这里我们就需要在meal_view_model里面使用filter_view_model里面的东西
这里我们就需要知道在meal_view_model里面 依赖filter_view_model
我们来到main.dart根目录
我们使用ChangeNotifierProxyProvider这个东西
这里我们就把这个 HYMealViewMode给删掉了
ChangeNotifierProxyProvider(
create: (ctx) => HYMealViewModel(),
update: ,
),
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qR5p8sdd-1589850162157)(82058C36988A4BBA9C37C5381D615BB0)]
这个updata是必传
这个 ChangeNotifierProxyProvider 是一个泛型类 他需要传两个泛型
我们的ChangeNotifierProvider 它也是一个泛型类 但是它只有一个参数 我们一般是不穿这个参数的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fu5PDChH-1589850162158)(F0D9A848DA164FED9AE261BAF5993C3A)]
为什么呢 因为你在最后返回的时候它会返回一个参数 这个东西就他的类型
所以这里我们一般都不传
但是这个ChangeNotifierProxyProvider它需要你传两个 所以你需要 中间有一个依赖
这两个泛型第一个是 要依赖的泛型
第二个是要返回的ViewModel
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PQr1JcUU-1589850162159)(6AF58BBF632C47288296E251E93E59BF)]
这两个泛型是那里用的呢
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0HFBUyLy-1589850162161)(B7DE6342398741AFBE605C40F442F9F6)]
它是在update里面的
这个两个泛型又是在函数中传递参数的时候使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WIRdJ98a-1589850162163)(BB73A0C6674F472D92DA562C521A5058)]
所以我们这里要这么写
ChangeNotifierProxyProvider(
create: (ctx) => HYMealViewModel(),
update: (ctx, filterVM, mealVM) {
return
},
),
然后我们可以在 MealViewModel里面拿到这个 filter_view_model里面的数据
meal_view_model.dart
class HYMealViewModel extends ChangeNotifier {
// 这里不初始化的就是null
List _meals = [];
HYFilterViewModel _filterVM;
List get meals {
return _meals.where((meal) {
// 做一个过滤: filterVM
}).toList();
}
void updateFilters(HYFilterViewModel filterVM) {
_filterVM = filterVM;
}
这样我们就可以在update将 这个filter放到这个 meal_view_model里面
ChangeNotifierProxyProvider(
create: (ctx) => HYMealViewModel(),
update: (ctx, filterVM, mealVM) {
mealVM.updateFilters(filterVM);
},
),
但是这里报了 一个警告因为这里要返回一个R
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aBEob1nA-1589850162165)(361E80315C234D1C8234B9CE1C09CAAA)]
我们这里是没有改的 所以我们这里 返回这个对象
ChangeNotifierProxyProvider(
create: (ctx) => HYMealViewModel(),
update: (ctx, filterVM, mealVM) {
mealVM.updateFilters(filterVM);
return mealVM;
},
),
注意这个ChangeNotifierProxyProvider必须卸载HYFilterViewModel导入Provider 地方的后面
void main() {
// Provider -> ViewModel / Provider / Consumer(Selector)
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => HYFilterViewModel(),
),
ChangeNotifierProxyProvider(
create: (ctx) => HYMealViewModel(),
update: (ctx, filterVM, mealVM) {
mealVM.updateFilters(filterVM);
return mealVM;
},
),
ChangeNotifierProvider(
create: (ctx) => HYFavorViewModel(),
),
],
child: MyApp(),
)
);
}
如果你改了当然就返回另外一个对象
我们这里就可以在meal_view_model里面做一个过滤了
List get meals {
return _meals.where((meal) {
// 做一个过滤: filterVM
// 我选了但是 食品没有这个属性 这个时候这个meal是不需要的
if( _filterVM.isGlutenFree && !meal.isGlutenFree ) return false;
}).toList();
}
我选了但是 食品没有这个属性 这个时候这个meal是不需要的 我们返回一个false就可以了
这个where函数和 其它地方的filter函数是一样的
import 'package:flutter/cupertino.dart';
import 'package:project03/core/model/meal_model.dart';
import 'package:project03/core/services/meal_request.dart';
import 'package:project03/core/viewmodel/filter_view_model.dart';
class HYMealViewModel extends ChangeNotifier {
// 这里不初始化的就是null
List _meals = [];
HYFilterViewModel _filterVM;
List get meals {
return _meals.where((meal) {
// 做一个过滤: filterVM
// 我选了但是 食品没有这个属性 这个时候这个meal是不需要的
if( _filterVM.isGlutenFree && !meal.isGlutenFree ) return false;
if( _filterVM.isVegetarian && !meal.isVegetarian ) return false;
if( _filterVM.isVegan && !meal.isVegan ) return false;
if( _filterVM.isLactoseFree && !meal.isLactoseFree ) return false;
return true;
}).toList();
}
void updateFilters(HYFilterViewModel filterVM) {
_filterVM = filterVM;
}
// 一旦你创建出对象 你就发送网络请求
HYMealViewModel() {
HYMealRequest.getMealData().then((res) {
_meals = res;
notifyListeners();
});
}
}
这样整个东西它就已经过滤了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xgt1rQWy-1589850162166)(42C4A2B5394D4267ACC665270F26CF4F)]
但是这里就会有一个bug了 我们如果在过滤之前收藏了一个 食物 然后过滤以后它还是会出现在收藏里面
所以我们的收藏也需要依赖这个东西
我们就要在对main进行一个修改
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sn7ozRr-1589850162167)(701255D61B1F4D05A1E2529D85007D65)]
我们要将这个Favor这个东西也依赖这个Filter
同样要对favor进行进行改变
我们来到meal_view_model.dart 拷贝对应的代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K9oJ6OWX-1589850162168)(E18450589F8D4DD3AA930E9E0D3DBF38)]
然后同样要对返回的东西 做一个改变 把这个东西复制到get里面
if( _filterVM.isGlutenFree && !meal.isGlutenFree ) return false;
if( _filterVM.isVegetarian && !meal.isVegetarian ) return false;
if( _filterVM.isVegan && !meal.isVegan ) return false;
if( _filterVM.isLactoseFree && !meal.isLactoseFree ) return false;
return true;
favor_view_model.dart
import 'package:flutter/cupertino.dart';
import 'package:project03/core/model/meal_model.dart';
import 'package:project03/core/viewmodel/filter_view_model.dart';
class HYFavorViewModel extends ChangeNotifier {
List _favorMeals = [];
HYFilterViewModel _filterVM;
void updateFilters(HYFilterViewModel filterVM) {
_filterVM = filterVM;
}
List get favorMeals {
return _favorMeals.where((meal) {
if( _filterVM.isGlutenFree && !meal.isGlutenFree ) return false;
if( _filterVM.isVegetarian && !meal.isVegetarian ) return false;
if( _filterVM.isVegan && !meal.isVegan ) return false;
if( _filterVM.isLactoseFree && !meal.isLactoseFree ) return false;
return true;
}).toList();
}
void addMeal(HYMealModel meal) {
_favorMeals.add(meal);
// 然后这里是要做一个通知的
notifyListeners();
}
void removeMeal(HYMealModel meal) {
_favorMeals.remove(meal);
notifyListeners();
}
bool isFavor(HYMealModel meal) {
return _favorMeals.contains(meal);
}
void handleMeal(HYMealModel meal) {
if (isFavor(meal)) {
removeMeal(meal);
} else {
addMeal(meal);
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dbniF9Dz-1589850162170)(54A701B06B7F4A1D8A0FB53F5C6053A4)]
我们就发现这个代码 很多都是拷贝的 既然是拷贝的 那我们的代码就因该存在很多的重复代码
所以我们就最好对这个代码进行一个抽取
如果是两个类中存在一个重复的代码 我们就只需要给他整一个基类就可以了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9A1fv4k6-1589850162171)(FCAD494BCD1C4B3ABAF2B5F3A0DAE1E8)]
创建一个对应的文件
但是我们在抽取的时候就发现 如果我们把整个的剪掉的话就发现 如果我们提取这些还不够
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xC5YpjJe-1589850162172)(23E01B6668A74F5190BB996BCB07D664)]
我们就需要提取 meal这种东西 favorMeals这种东西 但是这些都是名称的东西 所以我们是没有必要的
我们直接把这个剪掉
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WxX8ls7z-1589850162174)(9D5FECAAEAF340C398B39FC8F03C0DB6)]
然后把它拷过来
base_view_model.dart
import 'package:flutter/material.dart';
import 'package:project03/core/model/meal_model.dart';
import 'filter_view_model.dart';
class BaseMealViewModel extends ChangeNotifier {
// 这里不初始化的就是null
List _meals = [];
HYFilterViewModel _filterVM;
void updateFilters(HYFilterViewModel filterVM) {
_filterVM = filterVM;
}
List get meals {
return _meals.where((meal) {
// 做一个过滤: filterVM
// 我选了但是 食品没有这个属性 这个时候这个meal是不需要的
if( _filterVM.isGlutenFree && !meal.isGlutenFree ) return false;
if( _filterVM.isVegetarian && !meal.isVegetarian ) return false;
if( _filterVM.isVegan && !meal.isVegan ) return false;
if( _filterVM.isLactoseFree && !meal.isLactoseFree ) return false;
return true;
}).toList();
}
}
但是这里就有一个问题了
我们进行初始化的时候 需要给这个东西赋值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GjVO90rv-1589850162175)(C15E500103CD48509DB7C7E5865527F4)]
我们这里的meals是下滑线 我们是没有办法直接拿到的
所以我们给它搞一个setter 这个notifyListeners也因该放到这里来
set meals(List meal) {
_meals = meal;
notifyListeners();
}
这样我们的meal_view_model就变成了
import 'package:flutter/cupertino.dart';
import 'package:project03/core/model/meal_model.dart';
import 'package:project03/core/services/meal_request.dart';
import 'package:project03/core/viewmodel/base_view_model.dart';
import 'package:project03/core/viewmodel/filter_view_model.dart';
class HYMealViewModel extends BaseMealViewModel {
// 一旦你创建出对象 你就发送网络请求
HYMealViewModel() {
HYMealRequest.getMealData().then((res) {
meals = res;
});
}
}
同样对这个favor_view_model进行抽取
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qC1chP66-1589850162176)(9845A0986FF14D2EA91C5C40519CFA2C)]
继承了这个
但是有一个问题 就是我们可以把这些 addMeal 里面的 _favorMeals.add(meal) 直接改成meals可以吗
这里是不可以的 因为这个meals是过滤之后的meals它会生成一个新的meals
不是原来 meals
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fXqat3iB-1589850162177)(1F6973F421A54A75B45413A282BC1B5C)]
但是 我们这里又希望能在子类里面拿这个_meals那这里有一个方法就是不要搞下滑线了
就可以拿到了
但是如果我们搞了 _就不能在子类里面访问到了 所以我们再搞一个 getter
让子类能够访问到这个meals
import 'package:flutter/material.dart';
import 'package:project03/core/model/meal_model.dart';
import 'filter_view_model.dart';
class BaseMealViewModel extends ChangeNotifier {
// 这里不初始化的就是null
List _meals = [];
HYFilterViewModel _filterVM;
void updateFilters(HYFilterViewModel filterVM) {
_filterVM = filterVM;
}
List get meals {
return _meals.where((meal) {
// 做一个过滤: filterVM
// 我选了但是 食品没有这个属性 这个时候这个meal是不需要的
if( _filterVM.isGlutenFree && !meal.isGlutenFree ) return false;
if( _filterVM.isVegetarian && !meal.isVegetarian ) return false;
if( _filterVM.isVegan && !meal.isVegan ) return false;
if( _filterVM.isLactoseFree && !meal.isLactoseFree ) return false;
return true;
}).toList();
}
set meals(List meal) {
_meals = meal;
notifyListeners();
}
List get originMeals {
return _meals;
}
}
然后favor里面就简单了
import 'package:project03/core/model/meal_model.dart';
import 'package:project03/core/viewmodel/base_view_model.dart';
class HYFavorViewModel extends BaseMealViewModel {
void addMeal(HYMealModel meal) {
originMeals.add(meal);
// 然后这里是要做一个通知的
notifyListeners();
}
void removeMeal(HYMealModel meal) {
originMeals.remove(meal);
notifyListeners();
}
bool isFavor(HYMealModel meal) {
return originMeals.contains(meal);
}
void handleMeal(HYMealModel meal) {
if (isFavor(meal)) {
removeMeal(meal);
} else {
addMeal(meal);
}
}
}
page->favor->favor.dart
里面改一下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NcikAVDA-1589850162179)(B7FF9CB321F04B939D4847E0C992FD67)]
然后就可以了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7k64cb81-1589850162180)(1E8397CBDF244B3CA6C3D6D574748333)]
所以我们这里可以这样管理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-96n2frRT-1589850162182)(BE659546E26B4BA186CEE9E1A0D1B217)]
以前这个flutter的这个还不是这么写的
它更简单 但是现在他们把这个update 给抽离出来了
缓存的话就是本地化存储 但是这里我们不讲这个东西比较简单