App开发:购物车
来源:互联网 发布:淘宝领券链接 编辑:程序博客网 时间:2024/06/02 10:07
购物车的实现有多种方式,一直觉得实现起来有难度,不过只实现一部分,有简单到复杂,可能一步步的就实现了购物车。
实现方式一:RecyclerView
参考:Android:玩转购物车界面和逻辑只需要一层Recyclerview,一个二层for循环和三个属性
实现原理:对item中的view设置回调。
这是自己练习写的,只实现了购物车这一个界面,是假数据,可能有bug,不建议作为项目使用。大家可以看上面的参考,实现方式不同。
效果图:
实现功能:
- 点击“+”增加商品数量
- 点击“-”减少商品数量
- 点击–删除该商品
- 选中商铺则选中该商铺下的所有商品
- 若商铺下的商品都被选中,那么也选中商铺;有一个没选中,则不选中商铺
- 点击–则购物车的商品全部选中;反之,都不选
- 对–总价和商品件数时时更新
思路
为了避免Button等控件造成抢占点击事件的情况发生,item都由TextView+ImageView这些不含点击事件的控件组成。
布局:
在RecyclerView
中,item
有2种,一种是head
,一种是body
,根据getItemViewType(int position
来区分head
和body
加+减+删除+选中:
对于各TextView
在其点击事件的监听中,添加了回调,在MainActivity
中使用回调处理业务逻辑.
bug:
RecyclerView
滑动不流畅,感觉有卡顿。
代码
2种ViewType
先定义2中viewType:int
private static int ViewTypeHead = 0;private static int ViewTypeBody = 1;
再重写方法getItemViewType(int position)
@Overridepublic int getItemViewType(int position) { if (list.get(position) instanceof ShopBean) { return ViewTypeHead; } else { return ViewTypeBody; }}
接着创建ViewTyped
对应的ViewHolder
public class ItemHeadViewHolder extends RecyclerView.ViewHolder { ... public ItemHeadViewHolder(View itemView) { super(itemView); ... }}
public class ItemBodyViewHolder extends RecyclerView.ViewHolder { ... public ItemBodyViewHolder(View itemView) { super(itemView); ... }}
然后在方法onCreateViewHolder(...)
中返回不同的ViewHolder
@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == ViewTypeHead) { View itemView = View.inflate(parent.getContext(), R.layout.item_header, null); return new ItemHeadViewHolder(itemView); } else { View itemView = View.inflate(parent.getContext(), R.layout.item_body, null); return new ItemBodyViewHolder(itemView); }}
最后在方法onBindViewHolder(...)
中绑定数据
@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) { if (ViewTypeHead == getItemViewType(position)) { ... } else if (ViewTypeBody == getItemViewType(position)) { ... }}
这样就实现了复杂的RecyclerView
的显示,下面设置回调
+ 增加商品数量
Step1:回调:
//增加数量public interface OnAddListener { void addCount(int position);}public OnAddListener mOnAddListener;public void setmOnAddListener(OnAddListener mOnAddListener) { this.mOnAddListener = mOnAddListener;}
Step2:在onBindViewHolder(...)
声明回调
holder.tv_product_add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mOnAddListener.addCount(position); }});
Step3:在MainActivity
中使用
取出
position
对应的商品对象,将其数量+1,然后更新ui, notifyDataSetChanged()
adapter.setmOnAddListener(new MyAdapter.OnAddListener() { @Override public void addCount(int position) { CartlistBean info = (CartlistBean) list.get(position); info.setCount(info.getCount() + 1); adapter.notifyDataSetChanged(); }});
- 减少商品数量
Step1:回调:
public interface OnCutListener { void cutCount(int position);}public OnCutListener mOnCutListener;public void setmOnCutListener(OnCutListener mOnCutListener) { this.mOnCutListener = mOnCutListener;}
Step2:在onBindViewHolder(...)
声明回调
holder.tv_product_subtract.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mOnCutListener.cutCount(position); }});
Step3:在MainActivity
中使用回调并处理逻辑
取出
position
对应的商品对象,将其数量-1,若数量=1,则弹出Toast,然后更新ui, notifyDataSetChanged()
adapter.setmOnCutListener(new MyAdapter.OnCutListener() { @Override public void cutCount(int position) { CartlistBean info = (CartlistBean) list.get(position); if (info.getCount() > 1) { info.setCount(info.getCount() - 1); adapter.notifyDataSetChanged(); } else { Toast.makeText(context, "商品数量必须大于等于1", Toast.LENGTH_SHORT).show(); } }});
删除商品
Step1:回调:
public interface OnDeleteListener { void DeleteProduct(int position);}public OnDeleteListener mOnDeleteListener;public void setmOnDeleteListener(OnDeleteListener mOnDeleteListener) { this.mOnDeleteListener = mOnDeleteListener;}
Step2:在onBindViewHolder(...)
声明回调
holder.tv_product_delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mOnDeleteListener.DeleteProduct(position); }});
Step3:在MainActivity
中使用
从集合中删除
position
对应的对象,如果position-1
是商铺,而且position-1
是集合的最后一个或者position
也是店铺,那么也把position-1
删除掉,然后更新ui, notifyDataSetChanged()
adapter.setmOnDeleteListener(new MyAdapter.OnDeleteListener() { @Override public void DeleteProduct(int position) { list.remove(position); if (list.get(position - 1) instanceof ShopBean) { if (position-1 == (list.size() - 1)||list.get(position) instanceof ShopBean) { list.remove(position - 1); } } adapter.notifyDataSetChanged(); }});
选中店铺
Step1:回调:
public interface OnShopSelectListener { void selectShop(int position);}public OnShopSelectListener mOnShopSelectListener;public void setOnShopSelectListener(OnShopSelectListener mOnShopSelectListener) { this.mOnShopSelectListener = mOnShopSelectListener;}
Step2:在onBindViewHolder(...)
声明回调
holder.tv_shop_select.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mOnShopSelectListener.selectShop(position); }});
Step3:在MainActivity
中使用
选中position对应的商铺,从
position+1
开始循环,如是商铺则结束循环;若不是商铺,就是商品,则选中该商品,最后更新UI, adapter.notifyDataSetChanged()
。
adapter.setOnShopSelectListener(new MyAdapter.OnShopSelectListener() { @Override public void selectShop(int position) { //选中商铺 ShopBean info = (ShopBean) list.get(position); info.setShopSelect(!info.getShopSelect()); //选中商品 for (int i = position + 1; i < list.size(); i++) { if (list.get(i) instanceof ShopBean) { //是商铺,则结束循环 break; } else { //非商铺,选中[position + 1,i)之间的商品 CartlistBean info2 = (CartlistBean) list.get(i); info2.setSelect(info.getShopSelect()); } } adapter.notifyDataSetChanged(); }});
选中商品
Step1:回调:
public interface OnProductSelectListener { void selectProduct(int position);}public OnProductSelectListener mOnProductSelectListener;public void setOnProductSelectListener(OnProductSelectListener mOnPorductSelectListener) { this.mOnProductSelectListener = mOnPorductSelectListener;}
Step2:在onBindViewHolder(...)
声明回调
holder.tv_product_select.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mOnProductSelectListener.selectProduct(position); }});
Step3:在MainActivity
中使用
首先选中该
position
对应的商品,如果该商铺下的商品全选中了,那么选中该商铺,那么怎么判断该商铺下的商品全部被选中了呢?:
首先取出该
position
所在的商铺的position
,设置m
,在得到下一间商铺的position
,设置n
,选中(m,n)
之间的商品。关键就是怎么获取
m,n
的值?
m:
递减for
循环,如果list.get(i)
的类型是ShopBean
,那么m = i;
n:
递增for
循环,如果list.get(i)
的类型是ShopBean
,那么n = i;
,
若该商铺是最后一间商铺,那么n
设为集合的长度n = list.size();
adapter.setOnProductSelectListener(new MyAdapter.OnProductSelectListener() { @Override public void selectProduct(int position) { CartlistBean info = (CartlistBean) list.get(position); info.setSelect(!info.getIsSelect()); int m = 0;//商铺的position--该商品所在的商铺 int n = 0;//下一间商铺的position //取值m for (int i = position; i > 0; i--) { if (list.get(i) instanceof ShopBean) { m = i; break; } } //取值n for (int i = position; i < list.size(); i++) { if (list.get(i) instanceof ShopBean) { n = i; break; } else { n = list.size(); } } //将该商铺下的商品是否选中的而状态放入集合selectList ArrayList<Boolean> selectList = new ArrayList<>(); for (int i = m + 1; i < n; i++) { CartlistBean info2 = (CartlistBean) list.get(i); selectList.add(info2.getIsSelect()); } //如果全是true,那么商铺页选true ShopBean shopInfo = (ShopBean) list.get(m); if (selectList.contains(false)) { shopInfo.setShopSelect(false); } else { shopInfo.setShopSelect(true); } adapter.notifyDataSetChanged(); }});
全选
点击全选,那么选中所有商品,并显示总价和数量;
取消全选,那么取消所有商品,并显示总价和数量为0.
- 首先定义3个变量num 、totalPrice 、isCheckAll
,是:总数量 +总价格 + 是否全部选中,默认值分别是0,0.0F,false
,
- 点击“全选”按钮后,isCheckAll = !isCheckAll;
,根据isCheckAll
,判断是否选中店铺和商品
- 若是true,遍历集合,选中店铺和商品,同时计算商品数量和总价格。
- 若是false,遍历集合,不选中店铺和商品,同时将
num 、 totalPrice
的值设为0.
tv_check_all.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { num = 0; totalPrice = 0.0f; isCheckAll = !isCheckAll; if (isCheckAll) { for (int i = 0; i < list.size(); i++) { if (list.get(i) instanceof ShopBean) { ShopBean info = (ShopBean) list.get(i); info.setShopSelect(isCheckAll); } else { CartlistBean info = (CartlistBean) list.get(i); info.setSelect(isCheckAll); num = num + 1; totalPrice = totalPrice + Float.parseFloat(info.getPrice()) * Float.parseFloat(info.getPrice()); } } } else { for (int i = 0; i < list.size(); i++) { if (list.get(i) instanceof ShopBean) { ShopBean info = (ShopBean) list.get(i); info.setShopSelect(isCheckAll); } else { CartlistBean info = (CartlistBean) list.get(i); info.setSelect(isCheckAll); } } num = 0; totalPrice = 0.0f; } tv_check_all.setSelected(isCheckAll); adapter.notifyDataSetChanged(); tv_total_count.setText("共" + num + "件商品"); tv_total_price.setText("总价:" + totalPrice); }});
监控全局
- 当某一个商品被选中的时候,底部的总价格和总数量要及时更新。
- 当商品全部选中的时候,底部的“全选”也要选中
Step1:回调:
//监控购物车列表选中情况public interface OnRefreshListener { void refresh(boolean havaSelect);//是否有选中item //boolean havaSelect参数无效,去掉也可以}public OnRefreshListener mOnRefreshListener;public void setOnRefreshListener(OnRefreshListener mOnRefreshListener) { this.mOnRefreshListener = mOnRefreshListener;}
Step2:在onBindViewHolder(...)
声明回调
if (mOnRefreshListener != null) { mOnRefreshListener.refresh(true);}
Step3:在MainActivity
中使用
怎么计算总价和和总数量?
遍历集合,集合中的元素是商品,那么数量*价格,就是总价格;
totalCount = totalCount + info.getCount();
就是总数量。
怎么实现 当商品全部选中的时候,底部的“全选”也要选中?
遍历集合,如果有一个商品没被选中,就不是”全选,”那么结束循环,不改变
全选
的背景图片
反之,则改变全选
的背景图片。
adapter.setOnRefreshListener(new MyAdapter.OnRefreshListener() { @Override public void refresh(boolean havaSelect) { int totalCount = 0; float totalPrice = 0.0f; for (int i = 0; i < list.size(); i++) { if (list.get(i) instanceof CartlistBean) { CartlistBean info = (CartlistBean) list.get(i); if (info.getIsSelect()) { totalCount = totalCount + info.getCount(); totalPrice = totalPrice + info.getCount() * Float.parseFloat(info.getPrice()); } } } tv_total_count.setText("共" + totalCount + "件商品"); tv_total_price.setText("总价:" + totalPrice); //全部选中,那么底部勾选“全选” boolean isCheckAll = false; for (int i = 0; i < list.size(); i++) { if (list.get(i) instanceof CartlistBean) { CartlistBean info = (CartlistBean) list.get(i); if (!info.getIsSelect()) { isCheckAll = false; break; } else { isCheckAll = true; } } } tv_check_all.setSelected(isCheckAll); }});
Demo
https://git.oschina.net/shoppingmallProject/ShopCartDemo01
实现方式二:RecyclerView
item布局包含商铺和商品,
但只有下面2中情况才显示商铺名称,其余隐藏。
- 第一个
- (i+1)与i的店铺名称不同
下面是联系人列表
Contact contact = contacts.get(position);MyHolder holder = (MyHolder) viewHolder;//显示indexif (position == 0 || !contact.getIndex().equals(contacts.get(position - 1).getIndex())) { holder.tv_index.setVisibility(View.VISIBLE); holder.tv_index.setText(contact.getIndex());} else { holder.tv_index.setVisibility(View.GONE);}
实现方式三:ExpandableListView
https://github.com/louisgeek/LouisShopCart
- App开发:购物车
- 电商app开发架构设计优化购物车环节
- mui开发APP教程之仿天猫购物车
- App实战节选-购物车
- 购物车设计开发
- ios开发购物车开发
- 基于HTML5之APP购物车实现
- AppCan移动开发:仿口袋购物APP源码
- 购物车的开发流程
- java web 购物车开发
- 简易session购物车开发
- ASP.NET开发购物推车之购物车类
- Android商城App购物车规格联动选择
- flex开发卡片加入购物车(六)
- java web开发 购物车功能实现
- 购物车移动端开发体会
- 快速开发Android购物车项目
- Vue2.0开发购物车实例
- 一步集成侧滑(删除)菜单
- 《Refactoring》,Substitute Algorithm(替换算法)
- 主元素
- 清除WKWebView cookies
- Redis各种数据结构内存占用测试
- App开发:购物车
- Android Studio 常用快捷键
- linux USB驱动层次
- 使用js将简单的字符串转数字;截取字符串
- Linux配置防火墙,开启特定端口
- 调用js代码获取webView页面中的所有图片及点击事件
- Mysql转oracle之SQL区别
- Spring学习笔记一:装配Bean
- 一个循环体引发的思考