简单的购物车(全选,反选,结算)
时间:2019-01-19
本文章向大家介绍简单的购物车(全选,反选,结算),主要包括简单的购物车(全选,反选,结算)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
如何做购物车,在做购物车之前必须要缕清楚它里边的逻辑 如果不理解逻辑 就和搬代码的码农没什么区别了 所以我建议大家县缕清楚逻辑 在去敲代码
布局很low 大家就凑活着看吧 诶话不多说了 直接上代码
以下是本人做购物车时用到的几个依赖
//MetrialDesign:Design库 implementation 'com.android.support:design:28.+' //Butterknife:根据反射注入框架 implementation 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' //Brvah:RecyclerView快速开发框架 implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30' //SmartRefreshLayout implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-19' implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.0-alpha-19' //没有使用特殊Header,可以不加这行 //okgo //必须使用 implementation 'com.lzy.net:okgo:3.0.4' implementation 'com.google.code.gson:gson:2.8.5' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.8.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
vlues下的strings.xml 设置个标题
<resources> <string name="app_name">ShoppingCar</string> <string name="toolbar_name">购物车</string> <string name="hint_number">1</string> </resources>
先来个最外层的布局
activity_main.xml
<android.support.v7.widget.Toolbar android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorAccent" android:fitsSystemWindows="true" app:title="@string/toolbar_name"/> <com.scwang.smartrefresh.layout.SmartRefreshLayout android:id="@+id/srfl" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <android.support.v7.widget.RecyclerView android:id="@+id/review" android:layout_width="match_parent" android:layout_height="match_parent"></android.support.v7.widget.RecyclerView> </com.scwang.smartrefresh.layout.SmartRefreshLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:layout_gravity="center_vertical"> <CheckBox android:id="@+id/check_all" android:layout_width="wrap_content" android:layout_height="match_parent" android:text="全选"/> <Button android:layout_width="wrap_content" android:layout_height="match_parent" android:text="结算" android:layout_alignParentRight="true" android:gravity="center_vertical" android:paddingLeft="20dp" android:paddingRight="20dp" android:id="@+id/sum_price"/> <TextView android:id="@+id/money" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginRight="20dp" android:layout_toLeftOf="@+id/sum_price" android:gravity="center_vertical" android:text="总计:0元" /> </RelativeLayout>
先把最外层该布的局布上 接下来是第二层
review_check.xml
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <CheckBox android:id="@+id/check_All" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" /> <TextView android:id="@+id/shoper" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center" android:paddingLeft="5dp" android:text="店名" android:textSize="22sp" /> </LinearLayout> <android.support.v7.widget.RecyclerView android:id="@+id/review_goods" android:layout_width="match_parent" android:layout_height="wrap_content" />
接下来是第三层
review_goods.xml
<android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dp" fresco:cardCornerRadius="@dimen/dp_4" fresco:contentPaddingBottom="@dimen/dp_4"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="10dp"> <CheckBox android:id="@+id/shop_goods" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" /> <ImageView android:id="@+id/image" android:layout_width="50dp" android:layout_height="50dp" android:layout_toRightOf="@id/shop_goods" android:paddingLeft="5dp" android:src="@mipmap/ic_launcher" /> <LinearLayout android:layout_toRightOf="@id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:orientation="vertical"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ellipsize="end" android:hint="商品名称" android:maxEms="20" android:paddingLeft="5dp" android:textStyle="bold" /> <TextView android:gravity="center" android:id="@+id/price" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/title" android:layout_marginTop="@dimen/dp_10" android:hint="商品价格" /> <com.example.shopping_car.ui.widget.CounterView android:gravity="center" android:id="@+id/goods_counter" android:layout_width="match_parent" android:layout_height="30dp"/> </LinearLayout> </RelativeLayout> </android.support.v7.widget.CardView>
最后一个布局是设置加减器的 背景图片可以自己在网上下载 counter.xml
<Button android:id="@+id/decrease" android:layout_width="@dimen/dp_40" android:layout_height="@dimen/dp_40" android:padding="@dimen/dp_10" android:background="@drawable/decrease"/> <TextView android:id="@+id/shop_number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null" android:inputType="number" android:text="@string/hint_number"/> <Button android:id="@+id/add" android:layout_width="@dimen/dp_40" android:layout_height="@dimen/dp_40" android:padding="@dimen/dp_10" android:background="@drawable/add"/>
步入正题 购物车正事代码开始
由于本人使用mvp做的网络数据请求 所以分了ui 包 bean包下的信息Goods类就没必要发了,接口类Constant就给大家用吧
public class Constant { public static final String SHOPPINGCART_URL = "https://www.zhaoapi" + ".cn/product/getCarts?uid=71"; }
M V P 3层
public interface ShoppingCartContract { public interface ShoppingCartView{ public void showData(String mCartString); } public interface ShoppingCartPresenter<ShoppingCartView>{ //绑定---------* public void attachView(ShoppingCartContract.ShoppingCartView shoppingCartView); //解绑---------* public void detachView(ShoppingCartContract.ShoppingCartView shoppingCartView); public void requestData(); } public interface ShoppingCartModel{ public void containData(CallBack callBack); public interface CallBack{ public void CallBack(String mCartString); } } }
public class ShoppingCartModelImpl implements ShoppingCartContract.ShoppingCartModel { @Override public void containData(final CallBack callBack) { OkGo.<String>get(Constant.SHOPPINGCART_URL).execute(new StringCallback() { @Override public void onSuccess(Response<String> response) { String resposneData = response.body().toString(); //回传给P层 callBack.CallBack(resposneData); } }); } }
public class ShoppingCartPresenterImpl implements ShoppingCartContract .ShoppingCartPresenter { ShoppingCartContract.ShoppingCartView shoppingCartView; private SoftReference<ShoppingCartContract.ShoppingCartView> softReference; private ShoppingCartModelImpl model; @Override public void attachView(ShoppingCartContract.ShoppingCartView shoppingCartView) { this.shoppingCartView = shoppingCartView; softReference = new SoftReference<>(shoppingCartView); model = new ShoppingCartModelImpl(); } @Override public void detachView(ShoppingCartContract.ShoppingCartView shoppingCartView) { softReference.clear(); } @Override public void requestData() { model.containData(new ShoppingCartContract.ShoppingCartModel.CallBack() { @Override public void CallBack(String mCartString) { shoppingCartView.showData(mCartString); } }); } }
MianActivity中的逻辑代码 主要是看后边全选反选的代码逻辑
public class MainActivity extends AppCompatActivity implements ShoppingCartContract.ShoppingCartView, View.OnClickListener { @BindView(R.id.review) RecyclerView review; @BindView(R.id.srfl) SmartRefreshLayout srfl; @BindView(R.id.check_all) CheckBox checkAll; @BindView(R.id.sum_price) Button sumPrice; @BindView(R.id.money) TextView money; private Context context; private ShoppingCartPresenterImpl presenter; private ChexkAdapter adapter; private List<Goods.DataBean> beanList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); //获取P层对象 context = this; presenter = new ShoppingCartPresenterImpl(); presenter.attachView(this); presenter.requestData(); } @OnClick(R.id.check_all) public void onViewClicked() { } @Override public void showData(String mCartString) { //点击事件 checkAll.setOnClickListener(this); //数据解析展示 Goods goods = new Gson().fromJson(mCartString, Goods.class); //外层条目商家条目 beanList = goods.getData(); //Toast.makeText(this, "" + beanList, Toast.LENGTH_SHORT).show(); //设置布局管理器 LinearLayoutManager manager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); review.setLayoutManager(manager); //设置适配器 adapter = new ChexkAdapter(R.layout.review_check, beanList); review.setAdapter(adapter); //条目点击 adapter.SetOnChexItemClickLisenter(new ChexkAdapter.OnChexItemClickLisenter() { @Override public void CallBack() { boolean result = true; for (int i = 0; i < beanList.size(); i++) { //外层选中状态 boolean businessChecked = beanList.get(i).getBusinessChecked(checkAll.isChecked()); result = result & businessChecked; for (int j = 0; j < beanList.get(i).getList().size(); j++) { //里层选中状态 boolean goodsChecked = beanList.get(i).getList().get(j).getGoodsChecked(); result = result & goodsChecked; } } checkAll.setChecked(result); //计算总价 GoodsCounter(); } }); } private void GoodsCounter() { //对总价进行计算 double counter = 0; //外层条目 for (int i = 0; i < beanList.size(); i++) { //内层条目 for (int j = 0; j < beanList.get(i).getList().size(); j++) { //判断内层条目是否勾选 if (beanList.get(i).getList().get(j).getGoodsChecked() == true) { //获取商品数据*商品价格 double price = beanList.get(i).getList().get(j).getPrice(); int defalutNumber = beanList.get(i).getList().get(j).getDefalutNumber(); double goodsPrice = price * defalutNumber; counter = counter + goodsPrice; } } } money.setText(""+"总价:" + String.valueOf(counter)); } @Override public void onClick(View v) { //全选逻辑的处理 for (int i = 0; i < beanList.size(); i++) { //1.首先让我层的商家目录全部选中 beanList.get(i).setBusinessChecked(checkAll.isChecked()); //2.再让里层的商品目录全部选中 for (int j = 0; j < beanList.get(i).getList().size(); j++) { //beanList.get(i).getList().get(j).setGoodsChecked(checkAll.isChecked()); beanList.get(i).getList().get(j).setGoodsChecked(checkAll.isChecked()); } } adapter.notifyDataSetChanged(); //计算总价 GoodsCounter(); } }
ChexkAdapter
public class ChexkAdapter extends BaseQuickAdapter<Goods.DataBean,BaseViewHolder> { OnChexItemClickLisenter onChexItemClickLisenter; public interface OnChexItemClickLisenter{ public void CallBack(); } public void SetOnChexItemClickLisenter(OnChexItemClickLisenter onChexItemClickLisenter){ this.onChexItemClickLisenter = onChexItemClickLisenter; } public ChexkAdapter(int layoutResId, @Nullable List<Goods.DataBean> data) { super(layoutResId, data); } @Override protected void convert(final BaseViewHolder helper, final Goods.DataBean item) { //设置商家名称 helper.setText(R.id.shoper, item.getSellerName()); //设置商家下的子商品条目 RecyclerView reviewGoods = helper.getView(R.id.review_goods); //避免焦点抢占 final CheckBox check = helper.getView(R.id.check_All); check.setOnCheckedChangeListener(null); //************************************ //获取商家条目是否选中状态 check.setChecked(item.getBusinessChecked(check.isChecked())); //子条目内容(数据源) List<Goods.DataBean.ListBean> goodsList = item.getList(); Log.e("lcj","aaa"+goodsList); LinearLayoutManager manager = new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false); //设置子条目适配器 final GoodsAdapter goodsAdapter = new GoodsAdapter(R.layout.review_goods, goodsList); reviewGoods.setLayoutManager(manager); reviewGoods.setAdapter(goodsAdapter); //goodsAdapter.setOnGoodsItemAdapter(new GoodsAdapter.) //然后外层的商品类别条目需要控制里面的商品条目 goodsAdapter.SetOnGoodsItemClickLisenter(new GoodsAdapter.OnGoodsItemClickLisenter() { @Override public void CallBack() { //遍历获取所有子条目,只要有一个未勾选,商品类别也应该是未勾选 boolean result = true; for (int i = 0; i < item.getList().size(); i++) { result = result & item.getList().get(i).getGoodsChecked(); } check.setChecked(result); //刷新适配器 goodsAdapter.notifyDataSetChanged(); //把最后的状态进行回传 //把最后的状态进行回传 onChexItemClickLisenter.CallBack(); } }); check.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //获取商品类别勾选状态 //外层商品类别条目获取的关键 for (int i = 0; i < item.getList().size(); i++) { item.getList().get(i).setGoodsChecked(check.isChecked()); item.setBusinessChecked(check.isChecked()); notifyDataSetChanged(); //把最后的状态进行回传 onChexItemClickLisenter.CallBack(); } } }); } }
GoodsAdapter类
class GoodsAdapter extends BaseQuickAdapter<Goods.DataBean.ListBean, BaseViewHolder> { OnGoodsItemClickLisenter onGoodsItemClickLisenter; public interface OnGoodsItemClickLisenter{ public void CallBack(); } public void SetOnGoodsItemClickLisenter(OnGoodsItemClickLisenter onGoodsItemClickLisenter){ this.onGoodsItemClickLisenter = onGoodsItemClickLisenter; } public GoodsAdapter(int layoutResId, @Nullable List<Goods.DataBean.ListBean> data) { super(layoutResId, data); } @Override protected void convert(BaseViewHolder helper, final Goods.DataBean.ListBean item) { helper.setText(R.id.price, "¥:" + item.getPrice()); helper.setText(R.id.title, item.getTitle()); ImageView image = helper.getView(R.id.image); String imagesString = item.getImages(); String[] imagesStr = imagesString.split("\\|"); Glide.with(mContext).load(imagesStr[0]).into(image); //避免焦点抢占 final CheckBox shop_goods = helper.getView(R.id.shop_goods); shop_goods.setOnCheckedChangeListener(null); shop_goods.setChecked(item.getGoodsChecked()); //以接口的方式把状态回传给外层 shop_goods.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { //Bean对象状态进行更新完毕 item.setGoodsChecked(isChecked); onGoodsItemClickLisenter.CallBack(); } }); //加减器 CounterView counterView = helper.getView(R.id.goods_counter); counterView.SetOnCounterLisenter(new CounterView.OnCounterLisenter() { @Override public void onDecrese(int Snumber) { //对新增字段进行改正 item.setDefalutNumber(Snumber); onGoodsItemClickLisenter.CallBack(); } @Override public void onAdd(int Snumber) { item.setDefalutNumber(Snumber); onGoodsItemClickLisenter.CallBack(); } }); } }
由于加减器我是用自定义view做的 所以有个CounterView类
public class CounterView extends LinearLayout implements View.OnClickListener { private TextView number; private Button decrease; private Button add; public CounterView(Context context,AttributeSet attrs) { super(context,attrs); //填充的条目布局 View view = LayoutInflater.from(context).inflate(R.layout.counter, this); decrease = view.findViewById(R.id.decrease); add = view.findViewById(R.id.add); number = view.findViewById(R.id.shop_number); add.setOnClickListener(this); decrease.setOnClickListener(this); } @Override public void onClick(View v) { String numberString = number.getText().toString(); int Snumber = Integer.parseInt(numberString); switch (v.getId()){ case R.id.decrease: Snumber = Snumber - 1; //number.setText(String.valueOf(Snumber)); //Toast.makeText(getContext(),""+Snumber,Toast.LENGTH_LONG).show(); if (Snumber<0) { Snumber = 0; //最少数量为0 number.setText(String.valueOf(Snumber)); } number.setText(String.valueOf(Snumber)); //借口回调回传数字 onCounterLisenter.onDecrese(Snumber); break; case R.id.add: Snumber = Snumber + 1; number.setText(String.valueOf(Snumber)); //借口回掉回传数据 onCounterLisenter.onAdd(Snumber); break; } } OnCounterLisenter onCounterLisenter; public interface OnCounterLisenter{ //减少 public void onDecrese(int Snumber); //增加 public void onAdd(int Snumber); } public void SetOnCounterLisenter(OnCounterLisenter onCounterLisenter){ this.onCounterLisenter = onCounterLisenter; } }
代码也给大家弄完了 主要的逻辑 我在代码注释中也有 由于博主是个小白 大家可以看看 有什么不懂得可以下方评论 大家一起讨论 一起进步
- 使用贝叶斯做英文拼写检查(c#)
- 贝叶斯文本分类c#版
- weex里Vuex state使用storage持久化
- 网络字体@font-face 如何处理网页中的特殊字体
- python实现多变量线性回归(Linear Regression with Multiple Variables)
- 【美团技术团队博客】序列化和反序列化
- Java 静态代理与动态代理
- ELK日志套件安装与使用
- HTML知识复习
- MarkDown 常用语法教程
- CSS3盒阴影 box-shadow
- HTML5-类库系列 补讲AJAX
- HTML5-类库系列 事件与获取完成版样式
- 为什么不要在 JavaScript 中使用位操作符?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 熟悉又陌生的 k8s 字段:finalizers
- python+selenium 外部文件导入操作
- 小书MybatisPlus第1篇-整合SpringBoot快速开始增删改查
- K8S 生态周报| Istio v1.7.1 发布
- MongoDB设计方法及技巧
- 我要以血和泪的经历告诉你,这个 bug 太难解决了
- Loki和Fluentd的那点事儿
- 恕我直言你可能真的不会java第9篇-元素的匹配与查找
- 恕我直言你可能真的不会java第8篇-函数式接口
- 突破 DockerHub 限制,全镜像加速服务
- 恕我直言你可能真的不会java第7篇:像使用SQL一样排序集合
- K8S 生态周报| KIND v0.9 发布带来众多更新
- oracle 数据回滚,恢复误删的数据,闪回表功能的使用
- C语言 | 关于结构体内存对齐,看这篇就够了
- Python 图像处理篇-利用opencv库展示本地图片实例演示