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来区分headbody
加+减+删除+选中:
对于各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

0 0
原创粉丝点击