Flutter實(shí)現(xiàn)購(gòu)物車功能(代碼+邏輯)
一、初始化時(shí)判斷是否為登錄狀態(tài)
假設(shè)是登錄狀態(tài)從本地中取出token,帶參傳遞給后端請(qǐng)求登錄后購(gòu)物車數(shù)據(jù)
二、分析點(diǎn)擊全選和非全選狀態(tài)
1.全選狀態(tài)就是把數(shù)組中的數(shù)據(jù)對(duì)應(yīng)的每個(gè)check值設(shè)置為true,總價(jià)就是后端返回的全選數(shù)量的總價(jià)格
設(shè)置全選和非全選
這個(gè)的改變是由初始化查詢數(shù)組列表中是否為全選或非全選狀態(tài)所決定,如果遇見一個(gè)check為false那么就返回false
2.非全選狀態(tài)(總價(jià)結(jié)果為0或者當(dāng)前選中對(duì)象的總價(jià)之和)
判斷是否非全選狀態(tài)
三、改變單個(gè)物品check
觸發(fā)checkCart接口進(jìn)行更新全選狀態(tài)的總價(jià),以及當(dāng)前選中商品總價(jià)
四、點(diǎn)擊數(shù)量增加和減少按鈕改變當(dāng)前顯示number值
觸發(fā)update接口等更新數(shù)量,觸發(fā)查詢接口更改選中商品總價(jià),以及全選總價(jià)
自定義的數(shù)量組件返回的value是當(dāng)前增加或減少改變后的number值
五、長(zhǎng)按刪除數(shù)據(jù)
調(diào)用刪除接口重新渲染頁(yè)面
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> { //購(gòu)物車數(shù)據(jù)服務(wù) CartService _cartService = CartService(); //購(gòu)物車列表數(shù)據(jù) List<CartModel> _cartList; //購(gòu)物車列表數(shù)據(jù)模型 CartListModel _cartListModel; //是否登錄 bool _isLogin = false; //是否全選 bool _isAllCheck = false; //是否全都不選 bool _isAllNotCheck = false; //總計(jì) double _totalMoney; //token var token; //獲取當(dāng)前查詢購(gòu)物車中選中的商品數(shù)量 var _checkedGoodsAmount; @override void initState() { super.initState(); //從緩存中取出當(dāng)前登錄狀態(tài) SharedPreferencesUtil.getLoginSave().then((v){ print("登錄購(gòu)物車頁(yè)面獲取本地登錄值${v}"); if(v){ setState(() { _isLogin = v; }); //刷新購(gòu)物車數(shù)據(jù) //從緩存中取出當(dāng)前的token值 SharedPreferencesUtil.getToken().then((onValue) { if(onValue!=null){ _getCartData(onValue); setState(() { token = onValue; }); } }); } }); } _listener(){ //初始化的時(shí)候監(jiān)聽是否登錄 loginEventBus.on<LoginEvent>().listen((LoginEvent loginEvent) { print("購(gòu)物車頁(yè)面是否判定登錄"); setState(() { _isLogin = loginEvent.isLogin; }); }); } //獲取購(gòu)物車數(shù)據(jù) _getCartData(token) { print("---------${token}"); //將token值放入請(qǐng)求頭里 Options options = Options(headers:{"X-Shop-Token" : token}); //查詢購(gòu)物車數(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); } //判斷是否全部不選,如果有一個(gè)等于true就返回false _isNotCheckedAll(){ //迭代循環(huán)購(gòu)物車列表所有checked屬性,當(dāng)全部為true時(shí)為全選狀態(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)購(gòu)物車列表所有checked屬性,當(dāng)全部為true時(shí)為全選狀態(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)用戶從商品詳情頁(yè)面點(diǎn)擊添加至購(gòu)物車時(shí)會(huì)觸發(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("購(gòu)物車"), ), 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( "還沒有添加任何商品,快去選購(gòu)吧!", 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>[ //渲染購(gòu)物車列表數(shù)據(jù) ListView.builder( //購(gòu)物車列表項(xiàng)個(gè)數(shù) itemCount: _cartList.length, //購(gòu)物車列表項(xiàng)構(gòu)建器 itemBuilder: (BuildContext context, int index) { //根據(jù)索引返回列表項(xiàng) 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), //全選價(jià)格 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)到填寫訂單頁(yè)面 _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( "購(gòu)物車", 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)至填寫訂單頁(yè)面 _fillInOrder() { NavigatorUtil.goFillInOrder(context, 0); } //設(shè)置是否全選/全不選 _setCheckedAll(bool checked) { setState(() { _isAllCheck = checked; for (int i = 0; i < _cartList.length; i++) { _cartList[i].checked = checked; } }); } //刪除對(duì)話框 _deleteDialog(int index) { return showDialog<void>( context: context, barrierDismissible: true, builder: (BuildContext context) { return AlertDialog( //提示 title: Text(KString.TIPS), //是否確認(rèn)刪除 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ù)索引刪除購(gòu)物車商品 _deleteGoods(int index) { //獲取token值 Options options = Options(headers:{"X-Shop-Token" : token}); //通過(guò)索引獲取到產(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ù)索引獲取購(gòu)物車項(xiàng)組件 Widget _getCartItemWidget(int index) { return Container( height:130, width: double.infinity, child: InkWell( //長(zhǎng)按打開刪除商品對(duì)話框 onLongPress: () => _deleteDialog(index), child: Card( //水平布局 child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ //是否勾選此商品 Checkbox( //讀取購(gòu)物車列表數(shù)據(jù)中當(dāng)前項(xià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, ), ), //商品價(jià)格 Text( "¥${_cartList[index].price}", style: TextStyle( fontSize: 16, color: Colors.grey), ) ], ), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ //購(gòu)買商品數(shù)量 Text( "X${_cartList[index].number}", style: TextStyle( color: Colors.black54, fontSize: 16), ), Padding( padding: EdgeInsets.only( top:10, ), ), //使用購(gòu)物數(shù)量組件 CartNumberWidget(_cartList[index].number, (value) { //根據(jù)返回的索引及數(shù)量更新購(gòu)物車 _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)用購(gòu)物車數(shù)據(jù)服務(wù)方法 _cartService.cartCheck((success) { setState(() { _cartListModel = success; _cartList = _cartListModel.cartList; //重新設(shè)置全選狀態(tài) _isAllCheck = _isCheckedAll(); //計(jì)算總價(jià) _checkedGoodsAmount = _cartListModel.cartTotal.checkedGoodsAmount; _totalMoney = _cartListModel.cartTotal.goodsAmount; }); }, (error) { ToastUtil.showToast(error); }, parameters,options); } //更新購(gòu)物車,傳入索引及數(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實(shí)現(xiàn)購(gòu)物車功能(代碼+邏輯)的文章就介紹到這了,更多相關(guān)Flutter 購(gòu)物車內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Flutter實(shí)現(xiàn)頁(yè)面切換后保持原頁(yè)面狀態(tài)的3種方法
- Flutter 超實(shí)用簡(jiǎn)單菜單彈出框 PopupMenuButton功能
- Flutter中http請(qǐng)求抓包的完美解決方案
- flutter InkWell實(shí)現(xiàn)水波紋點(diǎn)擊效果
- Flutter中如何加載并預(yù)覽本地的html文件的方法
- flutter日期選擇器 flutter時(shí)間選擇器
- Flutter中如何實(shí)現(xiàn)無(wú)Context跳轉(zhuǎn)詳解
- flutter Toast實(shí)現(xiàn)消息提示框
相關(guān)文章
Android自定義圓環(huán)倒計(jì)時(shí)控件
這篇文章主要為大家詳細(xì)介紹了Android自定義圓環(huán)倒計(jì)時(shí)控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09Android Native 內(nèi)存泄漏系統(tǒng)化解決方案
這篇文章主要介紹了Android Native 內(nèi)存泄漏系統(tǒng)化解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Android開發(fā)之sqlite3命令行簡(jiǎn)單使用方法
這篇文章主要介紹了Android開發(fā)之sqlite3命令行簡(jiǎn)單使用方法,分析了Android增刪改查等常用sqlite3的數(shù)據(jù)庫(kù)操作命令使用方法,需要的朋友可以參考下2016-02-02Android開發(fā)基礎(chǔ)之創(chuàng)建啟動(dòng)界面Splash Screen的方法
這篇文章主要介紹了Android開發(fā)基礎(chǔ)之創(chuàng)建啟動(dòng)界面Splash Screen的方法,以實(shí)例形式較為詳細(xì)的分析了Android定制啟動(dòng)界面的布局及功能實(shí)現(xiàn)相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10Android實(shí)現(xiàn)氣泡動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)氣泡動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04