App开发:购物车
2016-11-22 17:58
148 查看
购物车的实现有多种方式,一直觉得实现起来有难度,不过只实现一部分,有简单到复杂,可能一步步的就实现了购物车。
实现原理:对item中的view设置回调。
这是自己练习写的,只实现了购物车这一个界面,是假数据,可能有bug,不建议作为项目使用。大家可以看上面的参考,实现方式不同。
点击“-”减少商品数量
点击–删除该商品
选中商铺则选中该商铺下的所有商品
若商铺下的商品都被选中,那么也选中商铺;有一个没选中,则不选中商铺
点击–则购物车的商品全部选中;反之,都不选
对–总价和商品件数时时更新
布局:
在
加+减+删除+选中:
对于各
再重写方法
接着创建
然后在方法
最后在方法
这样就实现了复杂的
Step2:在
Step3:在
取出
Step2:在
Step3:在
取出
Step2:在
Step3:在
从集合中删除
Step2:在
Step3:在
选中position对应的商铺,从
Step2:在
Step3:在
首先选中该
如果该商铺下的商品全选中了,那么选中该商铺,那么怎么判断该商铺下的商品全部被选中了呢?:
首先取出该
关键就是怎么获取
若该商铺是最后一间商铺,那么
取消全选,那么取消所有商品,并显示总价和数量为0.
- 首先定义3个变量
- 点击“全选”按钮后,
若是true,遍历集合,选中店铺和商品,同时计算商品数量和总价格。
若是false,遍历集合,不选中店铺和商品,同时将
当商品全部选中的时候,底部的“全选”也要选中
Step1:回调:
Step2:在
Step3:在
怎么计算总价和和总数量?
遍历集合,集合中的元素是商品,那么数量*价格,就是总价格;
怎么实现 当商品全部选中的时候,底部的“全选”也要选中?
遍历集合,如果有一个商品没被选中,就不是”全选,”那么结束循环,不改变
反之,则改变
但只有下面2中情况才显示商铺名称,其余隐藏。
第一个
(i+1)与i的店铺名称不同
下面是联系人列表
实现方式一: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:intprivate static int ViewTypeHead = 0; private static int ViewTypeBody = 1;
再重写方法
getItemViewType(int position)
@Override public 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
@Override public 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(...)中绑定数据
@Override public 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; //显示index if (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开发架构设计优化购物车环节
- mui开发APP教程之仿天猫购物车
- "卡秀"开发总结(NOKIA平台J2ME APP)
- Smart Client开发: 使用AppUpdater组件
- 开发ASP.NET 2.0 Web应用程序时如何将App_Code文件夹中的共享代码配置生成多个Dll
- JBuilder开发实践者之路--Appbrowser
- flex开发卡片加入购物车(六)
- 我看校内app应用的开发
- Ruby on rails开发从头来(windows)(九)-给购物车添加错误处理
- PC Camera开发日志(二)------ 流行Camera APP比较分析
- Web应用程序ASP.NET开发电子商务网站购物车
- 开放式开发/开源项目-TimeDog[C#WindowsApp]
- 购物车设计开发之一 —— 需求调研
- Ruby on rails开发从头来(windows)(八)-使用Session创建购物车
- Smart Client开发: 使用AppUpdater组件
- 购物车设计开发之二 —— 业务建模
- VB2005开发简单WindowsApp与2003几乎没有差别
- 购物车设计开发之二 —— 业务建模
- Ruby on rails开发从头来(windows)(十)-清空购物车和格式化金额
- 配置最优Google App Engine开发环境