美文网首页
Flower_gift 简单的Flutter实战app(六)

Flower_gift 简单的Flutter实战app(六)

作者: 浮桥小麦 | 来源:发表于2019-08-22 22:54 被阅读0次
    ed94bbb1f573dd5dcd00505fab7cfb72.png
    项目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("+"),
            ),
    
         );
      }
    
    }
    
    结尾:到此其实整个app最复杂的部分已经基本都完成了,剩下的一些我也许就不会放简书上了,等全部完成后,我会将项目上传到gitHub上。

    相关文章

      网友评论

          本文标题:Flower_gift 简单的Flutter实战app(六)

          本文链接:https://www.haomeiwen.com/subject/bghasctx.html