项目git地址:flower_gift
这次的内容是购物车界面的各种逻辑完成。还是先简单看看效果:
2222.gif先说明一下,对于Provide的运用,只要把购物车这一个页面的逻辑理清楚,用好这个数据管理,那么Provide的运用应该就没有什么大问题了。 其次是本来这个是有后台交互的购物车,这样没什么难度,我也就基本也按照技术胖的教学课程来重新做了一次购物车,收获蛮大的。 下面还是就分环节介绍吧
本地数据持久化方案-- shared_preferences
这个东西呢,有点像iOS中的NSUserDefaults,也是依靠键值对存储数据,可以存储一些像int,String,List等一些数据到本地,很轻量级,使用也比较方便,只需要简单学习一些就可以上手了
tabBar栏的简单的切换逻辑
在最初搭建页面框架的时候,我就已经创建了一个TabBarTapProvide来管理底部tab标签栏的切换,所以我们在商品详情页,要想直接跳转到购物车tab页面就很简单了
找到商品详情页的detailsBottom_widget
InkWell(
onTap: (){
//改变tab的选中index来控制底部tab的切换
Provide.value<TabBarTapProvide>(context).bottomTabBarTap(3);
//pop出当前页面
Navigator.pop(context);
},
在购物车点击里面加上这个代码即可
整个购物车Provide文件
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import '../model/cartInfo_model_entity.dart';
//购物车简单逻辑:
/*
* 因为我们这边购物车就不去和后台交互了,这样比较简单,我们就采用这个本地存储数据
* 的方式来做。
* 大概思路也就是在加入购物车的时候将商品的几个关键数据,先做成数据字典,然后加入到
* 购物车List中,最后将这个List转化为String存储,取出的时候,先将String转为List来进行操作
*
*/
final cartInfoKey = "cartInfo";
class CartProvide with ChangeNotifier{
String cartString = "[]";
List<CartInfoModel> cartList = [];
double allPrice = 0;//总价格
int allGoodsCount = 0;//商品总数量
bool isAllSelect = true;//是否全选
//存储商品
saveGoods(goodsId,goodsName,count,price,images) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
//首先获取数据库中的数据(String 类型)
cartString = prefs.getString(cartInfoKey);
//类型转换
var temp = cartString==null?[]:json.decode(cartString.toString());
List<Map> tempList = (temp as List).cast();
//加入购物车,判断购物车是否已有当前商品,有count++,没有就添加整个商品
bool isExist = false;//是否存在
int ival = 0;//临时索引
allPrice = 0;
allGoodsCount = 0;
tempList.forEach((item){
if(item["goodsId"] == goodsId){
//已经存在
tempList[ival]["count"] = item["count"]+1;
cartList[ival].count++;//数据模型++
isExist = true;
}
//判断商品否是选中状态
if(item["isCheck"]){
//商品数量和商品总价格计算
allPrice += (cartList[ival].price * cartList[ival].count);
allGoodsCount += cartList[ival].count;
}
});
//如果商品不存在
if(!isExist){
Map<String,dynamic> newGoods = {
"goodsId":goodsId,
"goodsName":goodsName,
"count":count,
"price":price,
"images":images,
"isCheck":true//默认加入购物车是选中的
};
tempList.add(newGoods);
cartList.add(
CartInfoModel.fromJson(newGoods)
);
allPrice += count * price;
allGoodsCount += count;
}
//持久化
cartString = json.encode(tempList).toString();//List=>String
print("购物车数据是:$cartString");
prefs.setString(cartInfoKey, cartString);
notifyListeners();
}
//清空购物车
removeCart() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove(cartInfoKey);
print("购物车已经清空");
notifyListeners();
}
//查询购物车
getCartInfo() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
cartString = prefs.getString(cartInfoKey);
cartList = [];
if(cartString == null){
cartList = [];
}else{
List<Map> tempList = (json.decode(cartString.toString()) as List).cast();
allPrice = 0;
allGoodsCount = 0;
isAllSelect = true;
tempList.forEach((item){
if(item["isCheck"]){
allPrice += (item["count"] * item["price"]);
allGoodsCount += item["count"];
}else{
isAllSelect = false;
}
cartList.add(CartInfoModel.fromJson(item));
});
}
notifyListeners();
}
//删除购物车商品
deleteSingleGoods(String goodsId) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
cartString = prefs.getString(cartInfoKey);
List<Map> tempList = (json.decode(cartString.toString()) as List).cast();
int tempIndex = 0;
int delIndex = 0;
//这个遍历只是获取这个要删除商品的索引,因为dart在循环中不能取修改List的内容
tempList.forEach((item){
if(item["goodsId"] == goodsId){
delIndex = tempIndex;
}
tempIndex++;
});
tempList.removeAt(delIndex);
cartString = json.encode(tempList).toString();
prefs.setString(cartInfoKey, cartString);
//重新获取购物车数据,刷新购物车界面
await getCartInfo();
}
//改变单个商品的选中状态
changeSelectState(CartInfoModel cartItem) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
cartString = prefs.getString(cartInfoKey);
List<Map> tempList = (json.decode(cartString.toString()) as List).cast();
int tempIndex = 0;
int changeIndex = 0;
tempList.forEach((item){
if(item["goodsId"] == cartItem.goodsId){
changeIndex = tempIndex;
}
tempIndex++;
});
//这里没有进行属性改变,是因为在点击勾选按钮的时候,已经对cartItem中的isCheck属性进行了改变
tempList[changeIndex] = cartItem.toJson();
cartString = json.encode(tempList).toString();
prefs.setString(cartInfoKey, cartString);
await getCartInfo();
}
//全选按钮操作
changeAllCheckBtnState(bool isSelect) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
cartString = prefs.getString(cartInfoKey);
List<Map> tempList = (json.decode(cartString.toString()) as List).cast();
List<Map> newList = [];
for(var item in tempList){
var newItem = item;
newItem["isCheck"] = isSelect;
newList.add(newItem);
}
cartString = json.encode(newList).toString();
prefs.setString(cartInfoKey, cartString);
await getCartInfo();
}
//商品数量加减
addOrReduceAction(CartInfoModel cartItem,String todo) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
cartString = prefs.getString(cartInfoKey);
List<Map> tempList = (json.decode(cartString.toString()) as List).cast();
int tempIndex = 0;
int changeIndex = 0;
tempList.forEach((item){
if(item["goodsId"] == cartItem.goodsId){
changeIndex = tempIndex;
}
tempIndex++;
});
if(todo == "add"){
cartItem.count++;
}else if(cartItem.count > 1){
cartItem.count--;
}
tempList[changeIndex] = cartItem.toJson();
cartString = json.encode(tempList).toString();
prefs.setString(cartInfoKey, cartString);
await getCartInfo();
}
}
逻辑不算复杂,但是各个操作比较多,得细心点,SharedPreferences的使用很简单,key最好单独提出来写成一个常量。还有就是dart语言的基础还是有必要去简单过一下,不然有些东西就只知道写这个,不知道为什么要写这个东东。
购物车界面
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../provide/cart_provide.dart';
import './cartSubWidget/cart_bottom.dart';
import './cartSubWidget/cart_item.dart';
class CarShopPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("购物车"),
),
body: FutureBuilder(
future: _getCartInfo(context),
builder: (context,snapshot){
if(snapshot.hasData){
List cartList = Provide.value<CartProvide>(context).cartList;
return Stack(
children: <Widget>[
Provide<CartProvide>(
builder: (context,child,value){
cartList = Provide.value<CartProvide>(context).cartList;
return ListView.builder(
itemCount: cartList.length,
itemBuilder: (context,index){
return CartItem(cartList[index]);
},
);
},
),
Positioned(
bottom: 0,
left: 0,
child: CartBottom(),
)
],
);
}else{
return Text("购物车是空的哦!");
}
},
),
);
}
//数据加载(本地获取)
Future<String> _getCartInfo(BuildContext context) async{
await Provide.value<CartProvide>(context).getCartInfo();
return "加载成功";
}
}
注意对于要实时更新的UI一定要放在Provide widget中
购物车拆分widget
cartItem.dart
import 'package:flutter/material.dart';
import '../../model/cartInfo_model_entity.dart';
import './cart_count.dart';//加减组件
import 'package:provide/provide.dart';
import '../../provide/cart_provide.dart';
class CartItem extends StatelessWidget {
final CartInfoModel item;
CartItem(this.item);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.fromLTRB(5.0, 2.0, 5.0, 2.0),
padding: EdgeInsets.fromLTRB(5.0, 10.0, 5.0, 10.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(width: 1,color:Colors.black12)
)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_cartCheckBtn(context,item),
_cartImage(context,item),
_cartGoodsName(context,item),
_cartPrice(context,item),
],
),
);
}
//选择按钮
Widget _cartCheckBtn(BuildContext context,CartInfoModel item){
return Container(
width: MediaQuery.of(context).size.width / 10,
child: Checkbox(
value: item.isCheck,
activeColor: Colors.orangeAccent,
onChanged: (bool val){
item.isCheck = val;//改变选中状态了
Provide.value<CartProvide>(context).changeSelectState(item);
},
),
);
}
//商品图片
Widget _cartImage(BuildContext context,CartInfoModel item){
return Container(
width: MediaQuery.of(context).size.width / 5,
padding: EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(width: 1,color: Colors.black12)
),
child: Image.network(item.images),
);
}
//商品名称
Widget _cartGoodsName(BuildContext context,CartInfoModel item){
return Container(
width: MediaQuery.of(context).size.width / 10 * 4,
padding: EdgeInsets.all(10.0),
alignment: Alignment.topLeft,
child: Column(
children: <Widget>[
Text(item.goodsName),
SizedBox(height: 10.0,),
CartCount(item)
],
),
);
}
//商品价格
Widget _cartPrice(BuildContext context,CartInfoModel item){
return Container(
width: MediaQuery.of(context).size.width / 10 * 2,
alignment: Alignment.centerRight,
child: Column(
children: <Widget>[
Text(
"¥${item.price}",
style: TextStyle(
color: Colors.orangeAccent
),
),
SizedBox(height: 15.0,),
Container(
child: InkWell(
onTap: (){
print("删除商品");
Provide.value<CartProvide>(context).deleteSingleGoods(item.goodsId);
},
child: Icon(
Icons.delete_forever,
color:Colors.black26,
size: 30.0,
),
),
)
],
),
);
}
}
cartBottom.dart
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/cart_provide.dart';
final double cartBottomFontS = 20.0;
class CartBottom extends StatelessWidget {
const CartBottom({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(5.0),
color: Colors.black12.withAlpha(15),
child: Provide<CartProvide>(
builder: (context,child,val){
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_selectAll(context),
_allPriceArea(context),
_goButton(context),
],
);
},
)
);
}
//全选按钮
Widget _selectAll(BuildContext context){
return Container(
width:(MediaQuery.of(context).size.width - 10)/10 * 3,
child: Row(
children: <Widget>[
Checkbox(
value: Provide.value<CartProvide>(context).isAllSelect,
activeColor: Colors.orangeAccent,
onChanged: (bool val){
print("点击了全选按钮");
Provide.value<CartProvide>(context).changeAllCheckBtnState(val);
},
),
Text("全选",
style: TextStyle(
fontSize: cartBottomFontS
),
)
],
),
);
}
//合计区域
Widget _allPriceArea(BuildContext context){
double allPrice = Provide.value<CartProvide>(context).allPrice;
return Container(
width:(MediaQuery.of(context).size.width - 10)/10 * 4,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
alignment: Alignment.centerRight,
child: Text("合计:",
style: TextStyle(
fontSize: cartBottomFontS
),
),
),
Container(
alignment: Alignment.centerLeft,
child: Text(
"¥${allPrice}",
style:TextStyle(
color:Colors.orangeAccent,
fontSize: cartBottomFontS,
)
),
)
],
),
],
),
);
}
//结算
Widget _goButton(BuildContext context){
int allGoodsCount = Provide.value<CartProvide>(context).allGoodsCount;
return Container(
width:(MediaQuery.of(context).size.width - 10)/10 *3,
height: 40.0,
padding: EdgeInsets.only(left: 10.0),
child: InkWell(
onTap: (){},
child: Container(
padding: EdgeInsets.all(10.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color:Colors.orangeAccent,
borderRadius: BorderRadius.circular(5.0)
),
child: Text(
"结算(${allGoodsCount})",
style:TextStyle(
color:Colors.white,
fontSize: 15.0,
)
),
),
),
);
}
}
cartCount.dart
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/cart_provide.dart';
import '../../model/cartInfo_model_entity.dart';
class CartCount extends StatelessWidget {
CartInfoModel item;
CartCount(this.item);
@override
Widget build(BuildContext context) {
var cWidth = (MediaQuery.of(context).size.width) / 10 * 4 * 0.7;
return Provide<CartProvide>(
builder: (context,child,val){
return Container(
width: cWidth,
margin: EdgeInsets.only(top: 5.0),
decoration: BoxDecoration(
border: Border.all(width: 1,color: Colors.black12)
),
child: Row(
children: <Widget>[
_reduceBtn(context,cWidth,item),
_countArea(context,cWidth,item),
_addBtn(context,cWidth,item)
],
),
);
},
);
}
//减少按钮
Widget _reduceBtn(BuildContext context,cWidth,CartInfoModel cartItem){
return InkWell(
onTap: (){
print("点击了减少按钮");
Provide.value<CartProvide>(context).addOrReduceAction(cartItem, "reduce");
},
child: Container(
width: cWidth / 4 +4,
height: cWidth / 4 * 0.8,
alignment: Alignment.center,
decoration: BoxDecoration(
color: item.count>1 ? Colors.white : Colors.black12,
border: Border(
right: BorderSide(width: 1,color:Colors.black12)
)
),
child: Text("-"),
),
);
}
//中间数字
Widget _countArea(BuildContext context,cWidth,CartInfoModel cartItem){
return Container(
width: cWidth / 4 * 2 -10.0,
height: cWidth / 4 * 0.8,
alignment: Alignment.center,
color: Colors.white,
child: Text("${cartItem.count}"),
);
}
//增加按钮
Widget _addBtn(BuildContext context,cWidth,CartInfoModel cartItem){
return InkWell(
onTap: (){
print("点击了加好按钮");
Provide.value<CartProvide>(context).addOrReduceAction(cartItem, "add");
},
child: Container(
width: cWidth / 4+4,
height: cWidth / 4 * 0.8,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
border: Border(
left: BorderSide(width: 1,color:Colors.black12)
)
),
child: Text("+"),
),
);
}
}
网友评论