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 = 0;//總價格 int allGoodsCount = 0;//商品總數 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=0;//foreach循環的索引 //循環判斷列表是否存在該goodsId的商品,如果有就數量+1 tempList.forEach((item){ if(item['goodsId']==goodsId){ tempList[ival]['count']=item['count']+1; 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;//價格先初始化為0 allGoodsCount=0;//數量先初始化為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=0;//定義循環的索引 int deleteIndex=0;//要刪除的索引 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=0;//歷史索引 int changeIndex=0;//改變的索引 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(430), child: Column( children: <Widget>[ Row( children: <Widget>[ Container( alignment: Alignment.centerRight, width: ScreenUtil().setWidth(280), child: Text( '合計:', style:TextStyle( fontSize:ScreenUtil().setSp(36) ) ), ), //紅色的價格 Container( alignment: Alignment.centerLeft, width: ScreenUtil().setWidth(150), child: Text( '${allPrice}', style: TextStyle( fontSize: ScreenUtil().setSp(36), color: Colors.red ) ), ) ], ), //第二行 Container( width: ScreenUtil().setWidth(430),//和第一行一樣寬 alignment: Alignment.centerRight, child: Text( '滿10元免配送費,預購免配送費', style: TextStyle( color: Colors.black38, fontSize: ScreenUtil().setSp(22) ), ), ) ], ), ); } //結算 用 inkWell Widget _goButton(context){ int allGoodsCount= Provide.value<CartProvide>(context).allGoodsCount; return Container( width: ScreenUtil().setWidth(160), 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 ), ), ), ), ); } }
