Flutter實現(xiàn)購物車功能(代碼+邏輯)
一、初始化時判斷是否為登錄狀態(tài)
假設(shè)是登錄狀態(tài)從本地中取出token,帶參傳遞給后端請求登錄后購物車數(shù)據(jù)




二、分析點擊全選和非全選狀態(tài)
1.全選狀態(tài)就是把數(shù)組中的數(shù)據(jù)對應(yīng)的每個check值設(shè)置為true,總價就是后端返回的全選數(shù)量的總價格


設(shè)置全選和非全選

這個的改變是由初始化查詢數(shù)組列表中是否為全選或非全選狀態(tài)所決定,如果遇見一個check為false那么就返回false
2.非全選狀態(tài)(總價結(jié)果為0或者當(dāng)前選中對象的總價之和)
判斷是否非全選狀態(tài)


三、改變單個物品check
觸發(fā)checkCart接口進行更新全選狀態(tài)的總價,以及當(dāng)前選中商品總價



四、點擊數(shù)量增加和減少按鈕改變當(dāng)前顯示number值
觸發(fā)update接口等更新數(shù)量,觸發(fā)查詢接口更改選中商品總價,以及全選總價


自定義的數(shù)量組件返回的value是當(dāng)前增加或減少改變后的number值



五、長按刪除數(shù)據(jù)
調(diào)用刪除接口重新渲染頁面

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:myshop_flutter/components/gradient_button.dart';
import 'package:myshop_flutter/config/colours.dart';
import 'package:myshop_flutter/config/index.dart';
import 'package:myshop_flutter/event/cart_number_event.dart';
import 'package:myshop_flutter/event/category_event.dart';
import 'package:myshop_flutter/event/login_event.dart';
import 'package:myshop_flutter/event/refresh_event.dart';
import 'package:myshop_flutter/model/cart_list_model.dart';
import 'package:myshop_flutter/page/CategoryPage/GoodCategory/GooddetailWidget/cart_number_widget.dart';
import 'package:myshop_flutter/service/cart_service.dart';
import 'package:myshop_flutter/utils/navigator_util.dart';
import 'package:myshop_flutter/utils/shared_preferences_util.dart';
import 'package:myshop_flutter/utils/toast_util.dart';
import 'package:myshop_flutter/widgets/cached_image_widget.dart';
import 'package:shared_preferences/shared_preferences.dart';
class CartPage extends StatefulWidget {
const CartPage({Key key}) : super(key: key);
@override
_CartPageState createState() => _CartPageState();
}
class _CartPageState extends State<CartPage> {
//購物車數(shù)據(jù)服務(wù)
CartService _cartService = CartService();
//購物車列表數(shù)據(jù)
List<CartModel> _cartList;
//購物車列表數(shù)據(jù)模型
CartListModel _cartListModel;
//是否登錄
bool _isLogin = false;
//是否全選
bool _isAllCheck = false;
//是否全都不選
bool _isAllNotCheck = false;
//總計
double _totalMoney;
//token
var token;
//獲取當(dāng)前查詢購物車中選中的商品數(shù)量
var _checkedGoodsAmount;
@override
void initState() {
super.initState();
//從緩存中取出當(dāng)前登錄狀態(tài)
SharedPreferencesUtil.getLoginSave().then((v){
print("登錄購物車頁面獲取本地登錄值${v}");
if(v){
setState(() {
_isLogin = v;
});
//刷新購物車數(shù)據(jù)
//從緩存中取出當(dāng)前的token值
SharedPreferencesUtil.getToken().then((onValue) {
if(onValue!=null){
_getCartData(onValue);
setState(() {
token = onValue;
});
}
});
}
});
}
_listener(){
//初始化的時候監(jiān)聽是否登錄
loginEventBus.on<LoginEvent>().listen((LoginEvent loginEvent) {
print("購物車頁面是否判定登錄");
setState(() {
_isLogin = loginEvent.isLogin;
});
});
}
//獲取購物車數(shù)據(jù)
_getCartData(token) {
print("---------${token}");
//將token值放入請求頭里
Options options = Options(headers:{"X-Shop-Token" : token});
//查詢購物車數(shù)據(jù)
_cartService.queryCart((cartList) {
setState(() {
_cartListModel = cartList;
_cartList = _cartListModel.cartList;
_checkedGoodsAmount = _cartListModel.cartTotal.checkedGoodsAmount;
_totalMoney = _cartListModel.cartTotal.goodsAmount;
});
//是否全選
_isAllCheck = _isCheckedAll();
_isAllNotCheck = _isNotCheckedAll();
}, (error) {
ToastUtil.showToast(error);
},options:options);
}
//判斷是否全部不選,如果有一個等于true就返回false
_isNotCheckedAll(){
//迭代循環(huán)購物車列表所有checked屬性,當(dāng)全部為true時為全選狀態(tài)
for (int i = 0; i < _cartList.length; i++) {
if (_cartList[i].checked == null || _cartList[i].checked ) {
return false;
}
}
return true;
}
// //判斷是否全選
bool _isCheckedAll() {
//迭代循環(huán)購物車列表所有checked屬性,當(dāng)全部為true時為全選狀態(tài)
for (int i = 0; i < _cartList.length; i++) {
if (_cartList[i].checked == null || !_cartList[i].checked) {
return false;
}
}
return true;
}
//監(jiān)聽刷新事件,當(dāng)用戶從商品詳情頁面點擊添加至購物車時會觸發(fā)刷新事件
_refreshEvent() {
//重新調(diào)用接口賦值
CarteventBus.on<RefreshEvent>().listen((RefreshEvent refreshEvent){
if(refreshEvent.isRefresh){
_getCartData(token);
}
});
CarteventBus.fire(RefreshEvent(
false
));
}
@override
Widget build(BuildContext context) {
//監(jiān)聽刷新事件
_listener();
_refreshEvent();
return _isLogin == true
? Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("購物車"),
),
body: _cartList.length == 0?
Container(
padding: EdgeInsets.only(top: 70),
child: Center(
child: Column(
children: [
Image.asset(
"images/emptycar.png",
width: 135,
height: 135,
),
SizedBox(
height: 46,
),
Text(
"還沒有添加任何商品,快去選購吧!",
style: TextStyle(
fontSize: 15, color: Colours.textBlack32),
),
SizedBox(
height: 80,
),
GestureDetector(
onTap: () {
// Navigator.pop(context);
},
child: Container(
alignment: Alignment.center,
width: 100,
height: 40,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colours.directBB1,
Colours.directBB2,
],
end: Alignment.bottomCenter,
begin: Alignment.topCenter,
),
borderRadius: BorderRadius.circular(150),
),
child: Text(
"去逛逛",
style: TextStyle(
color: Colors.white, fontSize: 16),
),
),
),
],
),
),
)
: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
//渲染購物車列表數(shù)據(jù)
ListView.builder(
//購物車列表項個數(shù)
itemCount: _cartList.length,
//購物車列表項構(gòu)建器
itemBuilder: (BuildContext context, int index) {
//根據(jù)索引返回列表項
return _getCartItemWidget(index);
}),
Container(
height: 60,
decoration:BoxDecoration(
color: Colors.white,
),
//水平布局
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 3,
child: Row(
children: [
//全選復(fù)選框
Checkbox(
value: _isAllCheck,
activeColor: KColor.defaultCheckBoxColor,
//選擇改變事件回調(diào)
onChanged: (bool) {
//設(shè)置是否全選
_setCheckedAll(bool);
}),
Text("全選"),
Expanded(
child: Container(
alignment: Alignment.centerRight,
margin: EdgeInsets.only(right: 20),
//全選價格
child: Text(_isAllCheck
? KString.TOTAL_MONEY +"${_totalMoney}"
: _isNotCheckedAll == true ? KString.TOTAL_MONEY +"0.0":KString.TOTAL_MONEY + "${_checkedGoodsAmount}"),
)),
],
)),
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(
right:
30,
),
alignment: Alignment.centerRight,
//結(jié)算按鈕
child: RaisedButton(
//結(jié)算操作
onPressed: () {
//跳轉(zhuǎn)到填寫訂單頁面
_fillInOrder();
},
color: KColor.defaultButtonColor,
child: Text(
//結(jié)算標(biāo)簽
KString.SETTLEMENT,
style: TextStyle(
color: Colors.white,
fontSize:17),
),
),
),
),
],
),
)
],
))
: Scaffold(
appBar: AppBar(
elevation: 0,
centerTitle: true,
title: Text(
"購物車",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.lightBlueAccent,
),
body: Container(
child: Column(
children: [
SizedBox(
height: 40,
),
Container(
alignment: Alignment.center,
child: Image.asset(
"images/wukong.png",
height: 60,
width: double.infinity,
),
),
Center(
child: Text("還沒有登錄哦"),
),
GestureDetector(
onTap: () {},
child: Padding(
padding: EdgeInsets.fromLTRB(30, 10, 30, 0),
child:
GradientButton("去登錄", 0xFFFF9E00, 0xFFFF4800, () {
NavigatorUtil.goLogin(context);
}, textSize: 18, textColor: 0xFFFEFEFE),
))
],
),
),
);
}
//跳轉(zhuǎn)至填寫訂單頁面
_fillInOrder() {
NavigatorUtil.goFillInOrder(context, 0);
}
//設(shè)置是否全選/全不選
_setCheckedAll(bool checked) {
setState(() {
_isAllCheck = checked;
for (int i = 0; i < _cartList.length; i++) {
_cartList[i].checked = checked;
}
});
}
//刪除對話框
_deleteDialog(int index) {
return showDialog<void>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
//提示
title: Text(KString.TIPS),
//是否確認刪除
content: Text(KString.DELETE_CART_ITEM_TIPS),
actions: <Widget>[
//取消按鈕
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
KString.CANCEL,
style: TextStyle(color: Colors.black54),
),
),
//刪除按鈕
FlatButton(
onPressed: () {
//刪除商品
_deleteGoods(index);
},
child: Text(
KString.CONFIRM,
style: TextStyle(color: KColor.defaultTextColor),
),
)
],
);
});
}
//根據(jù)索引刪除購物車商品
_deleteGoods(int index) {
//獲取token值
Options options = Options(headers:{"X-Shop-Token" : token});
//通過索引獲取到產(chǎn)品Id
var parameters = {
"productIds": [_cartList[index].productId]
};
//調(diào)用刪除商品方法
_cartService.deleteCart((success) {
//刪除成功提示
ToastUtil.showToast(KString.DELETE_SUCCESS);
setState(() {
//本地列表移除數(shù)據(jù)
_cartList.removeAt(index);
});
Navigator.pop(context);
}, (error) {
ToastUtil.showToast(error);
}, parameters,options:options);
}
//根據(jù)索引獲取購物車項組件
Widget _getCartItemWidget(int index) {
return Container(
height:130,
width: double.infinity,
child: InkWell(
//長按打開刪除商品對話框
onLongPress: () => _deleteDialog(index),
child: Card(
//水平布局
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
//是否勾選此商品
Checkbox(
//讀取購物車列表數(shù)據(jù)中當(dāng)前項的checked值
value: _cartList[index].checked ?? true,
activeColor: KColor.defaultCheckBoxColor,
//改變回調(diào)方法
onChanged: (bool) {
_checkCart(index, bool);
}),
//緩存商品圖片
CachedImageWidget(
80,
80,
//商品圖片路徑
_cartList[index].picUrl,
),
//垂直布局
SizedBox(width: 30,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//商品名稱
Text(
_cartList[index].goodsName,
style: TextStyle(
fontSize:16,
color: Colors.black54),
),
Padding(
padding: EdgeInsets.only(
top: 10,
),
),
//商品價格
Text(
"¥${_cartList[index].price}",
style: TextStyle(
fontSize: 16,
color: Colors.grey),
)
],
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//購買商品數(shù)量
Text(
"X${_cartList[index].number}",
style: TextStyle(
color: Colors.black54,
fontSize: 16),
),
Padding(
padding: EdgeInsets.only(
top:10,
),
),
//使用購物數(shù)量組件
CartNumberWidget(_cartList[index].number, (value) {
//根據(jù)返回的索引及數(shù)量更新購物車
_updateCart(index, value);
}),
],
))
],
),
),
),
);
}
//是否勾選商品,傳入索引及是否勾選
_checkCart(int index, bool isCheck) {
Options options = Options(headers:{"X-Shop-Token" : token});
var parameters = {
//產(chǎn)品Id
"productIds": [_cartList[index].productId],
//是否選擇
"isChecked": isCheck ? 1 : 0,
};
//調(diào)用購物車數(shù)據(jù)服務(wù)方法
_cartService.cartCheck((success) {
setState(() {
_cartListModel = success;
_cartList = _cartListModel.cartList;
//重新設(shè)置全選狀態(tài)
_isAllCheck = _isCheckedAll();
//計算總價
_checkedGoodsAmount = _cartListModel.cartTotal.checkedGoodsAmount;
_totalMoney = _cartListModel.cartTotal.goodsAmount;
});
}, (error) {
ToastUtil.showToast(error);
}, parameters,options);
}
//更新購物車,傳入索引及數(shù)量
_updateCart(int index, int number) {
Options options = Options(headers:{"X-Shop-Token" : token});
var parameters = {
//規(guī)格Id
"productId": _cartList[index].productId,
//商品Id
"goodsId": _cartList[index].goodsId,
//商品數(shù)量
"number": number,
//id
"id": _cartList[index].id,
};
_cartService.updateCart((success) {
setState(() {
_cartList[index].number = number;
});
_getCartData(token);
}, (error) {
ToastUtil.showToast(error);
cartNumberEventBus.fire(CartNumberEvent(number - 1));
}, options, parameters);
}
}
到此這篇關(guān)于Flutter實現(xiàn)購物車功能(代碼+邏輯)的文章就介紹到這了,更多相關(guān)Flutter 購物車內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中recyclerView底部添加透明漸變效果
這篇文章主要給大家介紹了關(guān)于Android中recyclerView如何實現(xiàn)底部添加透明漸變效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2018-04-04
android Animation監(jiān)聽器AnimationListener的使用方法)
AnimaitonListener的使用方法主要是在Animation上設(shè)置一個監(jiān)聽器,下面通過一個實例說明它的使用方法2013-11-11
Android 實現(xiàn)秒轉(zhuǎn)換成時分秒的方法
這篇文章主要介紹了Android 實現(xiàn)秒轉(zhuǎn)換成時分秒的方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05
Android 系統(tǒng)服務(wù)TelecomService啟動過程原理分析
這篇文章主要介紹了Android 系統(tǒng)服務(wù)TelecomService啟動過程原理分析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Android Service判斷設(shè)備聯(lián)網(wǎng)狀態(tài)詳解
本文主要介紹Android Service判斷聯(lián)網(wǎng)狀態(tài),這里提供了相關(guān)資料并附有示例代碼,有興趣的小伙伴可以參考下,幫助開發(fā)相關(guān)應(yīng)用功能2016-08-08

