Flutter实战视频-移动电商-60.购物车_全选按钮的交互效果制作
60.购物车_全选按钮的交互效果制作
主要做全选和复选框的这两个功能

provide/cart.dart
业务逻辑写到provide里面
先持久化取出来字符串,把字符串编程list。循环list

cart_page/cart_item.dart
每一项的复选框的事件

单个复选框的效果预览

全部取消,价格和数量都发生了变化

全选按钮
全选单独声明一个变量,

然后我们需要在获取全部购物车列表的方法里面做一些事情
循环之前先初始化为true,循环的时候只要是有没选中的那么全选就是false

cart_page/cart_bottom.dart

只要有一个没有选中,就不会都选中

全选中,全选的付款狂也是选中的状态

全选按钮的事件
provide/cart.dart中要单独写一个方法
新增点击全选和取消全选的方法


效果展示

点击后都取消了选择的状态

最终代码:
provide/cart.dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import '../model/cartInfo.dart'; class CartProvide with ChangeNotifier{
String cartString="[]";//声明一个变量 做持久化的存储
List<CartInfoModel> cartList=[];
double allPrice = ;//总价格
int allGoodsCount = ;//商品总数
bool isAllCheck=true;//全选 默认true //声明一个异步的方法,购物车操作放在前台不在请求后台的数据
save(goodsId,goodsName,count,price,images) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
cartString= prefs.getString('cartInfo');//先从持久化中获取
var temp = cartString==null?[]:json.decode(cartString.toString());
//声明list 强制类型是Map
List<Map> tempList=(temp as List).cast();//把temp转成list
bool isHave=false;//是否已经存在了这条记录
int ival=;//foreach循环的索引
//循环判断列表是否存在该goodsId的商品,如果有就数量+1
tempList.forEach((item){
if(item['goodsId']==goodsId){
tempList[ival]['count']=item['count']+;
cartList[ival].count++;
isHave=true;
}
ival++;
});
//没有不存在这个商品,就把商品的json数据加入的tempList中
if(!isHave){
Map<String,dynamic> newGoods={
'goodsId':goodsId,//传入进来的值
'goodsName':goodsName,
'count':count,
'price':price,
'images':images,
'isCheck':true
};
tempList.add(newGoods);
cartList.add(CartInfoModel.fromJson(newGoods));
}
cartString=json.encode(tempList).toString();//json数据转字符串
// print('字符串》》》》》》》》》》》${cartString}');
// print('字符串》》》》》》》》》》》${cartList}'); prefs.setString('cartInfo', cartString);
notifyListeners();
}
remove() async{
SharedPreferences prefs=await SharedPreferences.getInstance();
prefs.remove('cartInfo');
cartList=[];
print('清空完成----------------------');
notifyListeners();
} getCartInfo() async{
SharedPreferences prefs=await SharedPreferences.getInstance();
cartString=prefs.getString('cartInfo');//持久化中获得字符串
print('购物车持久化的数据================>'+cartString);
cartList=[];//把最终的结果先设置为空list
if(cartString==null){
cartList=[];//如果持久化内没有数据 那么就还是空的list
}else{
//声明临时的变量
List<Map> tempList=(json.decode(cartString.toString()) as List).cast();
allPrice=;//价格先初始化为0
allGoodsCount=;//数量先初始化为0
isAllCheck=true;//循环之前初始化一下
tempList.forEach((item){
if(item['isCheck']){
allPrice+=(item['count']*item['price']);
allGoodsCount +=item['count'];
}else{
isAllCheck=false;
}
cartList.add(CartInfoModel.fromJson(item));//json转成对象,加入到cartList中
}); }
notifyListeners();//通知
} //删除单个购物车商品
deleteOneGoods(String goodsId) async{
SharedPreferences prefs=await SharedPreferences.getInstance();
cartString=prefs.getString('cartInfo');
List<Map> tempList=(json.decode(cartString.toString()) as List).cast();
int tempIndex=;//定义循环的索引
int deleteIndex=;//要删除的索引
tempList.forEach((item){
if(item['goodsId']==goodsId){
deleteIndex=tempIndex;
}
tempIndex++;
});
tempList.removeAt(deleteIndex);//删除
//删除后转换成string进行持久化
cartString=json.encode(tempList).toString();//list转字符串
prefs.setString('cartInfo', cartString);
await getCartInfo();//重新获取下列表数据,因为getCartInfo方法里面有通知,这里就不再调用了
} changeCheckState(CartInfoModel cartItem) async{
SharedPreferences prefs=await SharedPreferences.getInstance();
cartString=prefs.getString('cartInfo');
List<Map> tempList=(json.decode(cartString.toString()) as List).cast();
int tempIndx=;//历史索引
int changeIndex=;//改变的索引
tempList.forEach((item){
if(item['goodsId']==cartItem.goodsId){
changeIndex=tempIndx;
}
tempIndx++;
}); tempList[changeIndex]=cartItem.toJson();//toJson就变成了Map值
cartString=json.encode(tempList).toString();
prefs.setString('cartInfo', cartString); await getCartInfo();//再次重新获取购物车的数据
} //点击全选按钮操作
changeAllCheckBtnState(bool isCheck) async{
SharedPreferences prefs=await SharedPreferences.getInstance();
cartString=prefs.getString('cartInfo');
List<Map> tempList=(json.decode(cartString.toString()) as List).cast();
List<Map> newList=[];//这里必须初始化为[]声明为一个空的值 for(var item in tempList)
{
//dart在循环的时候是不允许改变老的值的
var newItem=item;//把老的item赋值给新的item
newItem['isCheck']=isCheck;
newList.add(newItem);
} cartString=json.encode(newList).toString();
prefs.setString('cartInfo', cartString); await getCartInfo();//最后中心获取一下购物车的列表数据
} }
cart_bottom.dart
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provide/provide.dart';
import '../../provide/cart.dart'; class CartBottom extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(5.0),
color: Colors.white,
child: Provide<CartProvide>(
builder: (context,child,val){
return Row(
children: <Widget>[
_selectAllBtn(context),
_allPriceArea(context),
_goButton(context)
],
);
}
)
);
}
//全选
Widget _selectAllBtn(context){
bool isAllCheck=Provide.value<CartProvide>(context).isAllCheck;
return Container(
child: Row(
children: <Widget>[
Checkbox(
value: isAllCheck,
activeColor: Colors.pink,//激活的颜色
onChanged: (bool val){
Provide.value<CartProvide>(context).changeAllCheckBtnState(val);
},//事件
),
Text('全选')
],
),
);
}
//合计
Widget _allPriceArea(context){
double allPrice = Provide.value<CartProvide>(context).allPrice;
return Container(
width: ScreenUtil().setWidth(),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
alignment: Alignment.centerRight,
width: ScreenUtil().setWidth(),
child: Text(
'合计:',
style:TextStyle(
fontSize:ScreenUtil().setSp()
)
),
),
//红色的价格
Container(
alignment: Alignment.centerLeft,
width: ScreenUtil().setWidth(),
child: Text(
'${allPrice}',
style: TextStyle(
fontSize: ScreenUtil().setSp(),
color: Colors.red
)
),
)
],
),
//第二行
Container(
width: ScreenUtil().setWidth(),//和第一行一样宽
alignment: Alignment.centerRight,
child: Text(
'满10元免配送费,预购免配送费',
style: TextStyle(
color: Colors.black38,
fontSize: ScreenUtil().setSp()
),
),
)
],
),
);
} //结算 用 inkWell
Widget _goButton(context){
int allGoodsCount= Provide.value<CartProvide>(context).allGoodsCount;
return Container(
width: ScreenUtil().setWidth(),
padding: EdgeInsets.only(left:10.0),
child: InkWell(
onTap: (){},
child: Container(
padding: EdgeInsets.all(10.0),
alignment: Alignment.center,//居中对齐
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(3.0)//圆角
),
child: Text(
'结算(${allGoodsCount})',
style: TextStyle(
color: Colors.white
),
),
),
),
);
}
}
Flutter实战视频-移动电商-60.购物车_全选按钮的交互效果制作的更多相关文章
- Flutter实战视频-移动电商-63.购物车_详细页显示购物车商品数量
63.购物车_详细页显示购物车商品数量 购物车的图标嵌套在statck组件里面 外层套了一个stack组件 数量我们需要用Provide 返回一个container来做样式 气泡效果,中间是个数字外面 ...
- Flutter实战视频-移动电商-52.购物车_数据模型建立和Provide修改
52.购物车_数据模型建立和Provide修改 根据json数据生成模型类 {,"price":830.0,"images":"http://imag ...
- Flutter实战视频-移动电商-53.购物车_商品列表UI框架布局
53.购物车_商品列表UI框架布局 cart_page.dart 清空原来写的持久化的代码; 添加对应的引用,stless生成一个静态的类.建议始终静态的类,防止重复渲染 纠正个错误,上图的CartP ...
- Flutter实战视频-移动电商-54.购物车_商品列表子项布局
54.购物车_商品列表子项布局 子项做成一个单独的页面 新建cartItem.dart文件 新建cart_page文件夹,在里面新建cart_item.dart页面, 页面名字叫做CartItem 定 ...
- Flutter实战视频-移动电商-55.购物车_底部结算栏UI制作
55.购物车_底部结算栏UI制作 主要做下面结算这一栏目 cart_bottom.dart页面 先设置下内边距 拆分成三个子元素 全选 因为有一个文本框和一个全选的text文本,所以这里也用了Row布 ...
- Flutter实战视频-移动电商-56.购物车_商品数量控制区域制作
56.购物车_商品数量控制区域制作 主要做购物车中的数量这里 cart_page文件夹下新建cart_count.dart 减少按钮 因为会有点击事件,所以这里我们使用InkWell. child里面 ...
- Flutter实战视频-移动电商-57.购物车_在Model中增加选中字段
57.购物车_在Model中增加选中字段 先修改model类 model/cartInfo.dart类增加是否选中的属性 修改provide 修改UI部分pages/cart_page/cart_it ...
- Flutter实战视频-移动电商-58.购物车_删除商品功能制作
58.购物车_删除商品功能制作 主要做购物车后面的删除按钮 删除的方法写在provide里面 provide/cart.dart文件 传入goodsId,循环对比,找到后进行移除 //删除单个购物车商 ...
- Flutter实战视频-移动电商-59.购物车_计算商品价格和数量
59.购物车_计算商品价格和数量 本节课主要是加上自动计算的功能 provide/cart.dart 在provide的类里面增加两个变量 cart_bottom.dart 三个组件因为我们都需要套一 ...
随机推荐
- 在Linux中将php-fpm配置成服务的方法
1.配置php-fpm.conf vi /usr/local/php/etc/php-fpm.conf php-fpm.pid 目录必须指向:/usr/local/php/var/run/php-fp ...
- multimap容器和multiset容器中的find操作
前言 multimap容器是map容器的“ 增强版 ”,它允许一个键对应多个值.对于map容器来说,find函数将会返回第一个键值匹配元素所在处的迭代器.那么对于multimap容器来说,find函数 ...
- Storage,Memcache,KVDB都是存储服务,如何区分何时用何种服务
Storage :是SAE为开发者提供的分布式文件存储服务,用来存放用户的持久化存储的文件.用户需要先在在线管理平台创建Domain(相当于一级子目录). Storage为开发者提供分布式文件存 ...
- 未开启HugePages ORACLE session剧增时引起的一次悲剧
故障简单描写叙述一下:LINUX系统未开启HugePages,主机内存将近300G.SWAP是32G.ORACLE 的 SGA_MAX_SIZE设置是主机内存的将近80%,SGA_TARGET设置是主 ...
- windows下使用ofstream默认输出内存数据到文件中时,会自动将0A换成0A0D
0A即\n,而0D是\r,windows下换行是\n\r,因此会自动转换. 但是,这样会带来很大的问题,导致由内存写入文件中的数据和内存中不一样,还不知道是什么原因造成的. 特别是将从网络接收来的pn ...
- 使用 Visual Studio Code 运行 C# 及 Java 程序
背景 很多情况下,我只是想要编写一个非常简单的 C# 或者 Java 程序,只有几行代码,看看运行结果而已.虽说 Visual Studio / Eclipse / IntelliJ IDEA 功能强 ...
- 云计算系列——HIVE1.2.1 环境搭建
hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行. 其优点是学习成本低,可以通过 ...
- Unity编译时找不到AndroidSDK的问题 | Unable to list target platforms
解决方式 1.从官网下载一个旧版本的 Android SDK tools 25.2.3.tools_r25.2.3-windows.zip. 2. 解压 3. 替换原来sdk目录下tools
- DTLS学习笔记 -- RFC 4347- 6347
想学习一下dtls,是因为想以后没有公司免费VPN可用的时候,我能买一个主机,自己建一个VPN. 1.介绍 Web, email大多用TLS协议来做安全的网络传输,它们必须跑在可靠的TCP传输通道里. ...
- DNS常见攻击与防范
DNS常见攻击与防范 转自:http://www.williamlong.info/archives/3813.html 日期:2015-7-10 随着网络的逐步普及,网络安全已成为INTERNET路 ...