Android购物车

来源:互联网 发布:ubuntu下安装tar.gz 编辑:程序博客网 时间:2024/06/06 07:22

这里我用到的都是Android自带SDK中的资源,做了一个极其简单的购物车实现,总结购物车难点包含两个方面:

1、CheckBox的联动:

全选框、商铺复选框以及商品复选框要做到滴水不漏的联动,我的经验是在监听多选框时尽量采用click事件,避免使用checkChange事件(因为它总是能在你意想不到的地方调用),全选框可以通过商品价格来判断,这个在代码中也有体现。

2、数据的联动和UI的联动:

适配器的都是在外部类创建,而总价格等控件都是在调用适配器的地方,这个要做到联动,最简单的方式必然就是接口的回调,熟练使用可以节省很多代码,提高编程效率。

再有一个比较容易出现问题的地方就在于,我们经常是首先更改数据,然后通知适配器刷新数据(notifyDataSetChanged()),这里要注意的一点就是在更新数据的时候,一定确保更新的传递到适配器中的数据集合,否则会发现这个更新适配器的方法是无效的。


其他相关问题代码中均有体现,如果和我一样是一个编程小白,仔细阅读会有收获滴。


代码中没有添加自己的资源,逻辑都有实现就是UI丑了一点害羞

activity_main:

<?xml version="1.0" encoding="utf-8"?><LinearLayout    android:orientation="vertical"    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.bwie.test.test1025two.MainActivity">    <RelativeLayout        android:layout_gravity="center_horizontal"        android:background="@color/colorAccent"        android:layout_width="match_parent"        android:layout_height="50dp">        <TextView            android:textSize="38sp"            android:gravity="center"            android:textColor="#fff"            android:text="购物车"            android:layout_width="match_parent"            android:layout_height="wrap_content" />        <TextView            android:textColor="#fff"            android:textSize="38sp"            android:layout_alignParentRight="true"            android:text="2"            android:id="@+id/main_num"            android:layout_width="wrap_content"            android:layout_height="wrap_content" />    </RelativeLayout>    <ExpandableListView        android:layout_weight="1"        android:id="@+id/expand_able_view"        android:layout_width="match_parent"        android:layout_height="match_parent"/>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content">        <CheckBox            android:layout_weight="1"            android:id="@+id/main_check_all"            android:text="全选"            android:layout_width="0dp"            android:layout_height="wrap_content" />        <TextView            android:id="@+id/main_price"            android:gravity="center_horizontal"            android:text="0"            android:layout_weight="1"            android:layout_width="0dp"            android:layout_height="wrap_content" />        <Button            android:id="@+id/btn_delete"            android:background="#aaa"            android:layout_weight="1"            android:text="删除"            android:layout_width="0dp"            android:layout_height="wrap_content" />        <Button            android:id="@+id/btn_buy"            android:background="#f99"            android:layout_weight="1"            android:text="购买"            android:layout_width="0dp"            android:layout_height="wrap_content" />    </LinearLayout></LinearLayout>

group_item:

注:这里图了个简单,商铺名称我是通过设置CheckBox的text来显示的,另外取消焦点是为了不影响二级列表的点击展开与收回子集列表

<?xml version="1.0" encoding="utf-8"?><LinearLayout    android:orientation="horizontal"    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <CheckBox        android:focusable="false"        android:id="@+id/group_check"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></LinearLayout>

child_item:

<?xml version="1.0" encoding="utf-8"?><LinearLayout    android:orientation="horizontal"    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <CheckBox        android:id="@+id/child_check"        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <ImageView        android:id="@+id/child_img"        android:scaleType="center"        android:src="@mipmap/ic_launcher"        android:layout_width="80dp"        android:layout_height="80dp" />    <TextView        android:id="@+id/child_price"        android:textSize="22sp"        android:textColor="@color/colorPrimary"        android:text="2888"        android:layout_width="wrap_content"        android:layout_height="80dp" />    <RelativeLayout        android:layout_weight="1"        android:layout_width="match_parent"        android:layout_height="80dp">        <TextView            android:text="名字"            android:id="@+id/child_name"            android:layout_width="wrap_content"            android:layout_height="wrap_content" />        <LinearLayout            android:orientation="horizontal"            android:layout_alignParentBottom="true"            android:layout_width="wrap_content"            android:layout_height="wrap_content">            <TextView                android:id="@+id/child_jian"                android:gravity="center_horizontal"                android:text="—"                android:layout_width="30dp"                android:layout_height="30dp" />            <TextView                android:gravity="center_horizontal"                android:text="2"                android:id="@+id/child_num"                android:layout_width="30dp"                android:layout_height="30dp" />            <TextView                android:id="@+id/child_jia"                android:gravity="center_horizontal"                android:text="+"                android:layout_width="30dp"                android:layout_height="30dp" />        </LinearLayout>    </RelativeLayout></LinearLayout>


groupBean:

package com.bwie.test.test1025two;import java.util.ArrayList;/** * Created by Zzw on 2017/10/25. */public class Group {    private String name;    private boolean check;    private ArrayList<Child> children;    public Group(String name, boolean check,ArrayList<Child> children) {        this.name = name;        this.check = check;        this.children = children;    }    public Group() {    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public boolean isCheck() {        return check;    }    public void setCheck(boolean check) {        this.check = check;    }    public void setChildren(ArrayList<Child> children){        this.children = children;    }    public ArrayList<Child> getChildren(){        return children;    }    @Override    public String toString() {        return "Group{" +                "name='" + name + '\'' +                ", check=" + check +                '}';    }}

childBean:

package com.bwie.test.test1025two;/** * Created by Zzw on 2017/10/25. */public class Child {    private String name;    private String img;    private int num;    private boolean check;    private int price;    public Child(String name, String img, int num, boolean check, int price) {        this.name = name;        this.img = img;        this.num = num;        this.check = check;        this.price = price;    }    public Child() {    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getImg() {        return img;    }    public void setImg(String img) {        this.img = img;    }    public int getNum() {        return num;    }    public void setNum(int num) {        this.num = num;    }    public boolean isCheck() {        return check;    }    public void setCheck(boolean check) {        this.check = check;    }    public int getPrice() {        return price;    }    public void setPrice(int price) {        this.price = price;    }    @Override    public String toString() {        return "Child{" +                "name='" + name + '\'' +                ", img='" + img + '\'' +                ", num=" + num +                ", check=" + check +                ", price=" + price +                '}';    }}


MyAdapter:

package com.bwie.test.test1025two;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseExpandableListAdapter;import android.widget.CheckBox;import android.widget.ImageView;import android.widget.TextView;import java.util.ArrayList;/** * Created by Zzw on 2017/10/25. */public class MyAdapter extends BaseExpandableListAdapter {    Context context;    ArrayList<Group> groups;    public MyAdapter(Context context, ArrayList<Group> groups) {        this.context = context;        this.groups = groups;    }    //监听加减事件回调接口    public interface onNumChangeListener{        void onNumChange(int groupID,int childID,boolean isAdd);    }    private onNumChangeListener mOnNumChangeListener;    public void setOnNumChangeListener(onNumChangeListener mOnNumChangeListener){        this.mOnNumChangeListener = mOnNumChangeListener;    }    //监听多选框点击事件回调接口。    public interface onCheckChangeListener{        void onGroupClick(int groupID);        void onChildClick(int groupID,int childID);    }    private onCheckChangeListener mOnCheckChangeListener;    public void setmOnCheckChangeListener(onCheckChangeListener mOnCheckChangeListener){        this.mOnCheckChangeListener = mOnCheckChangeListener;    }    //监听价格需要更新回调接口    public interface onShouldChangeMoneyListener{        void onShouldChnageMoney();    }    private onShouldChangeMoneyListener mOnShouldChangeMoneyListener;    public void setmOnShouldChangeMoneyListener(onShouldChangeMoneyListener mOnShouldChangeMoneyListener){        this.mOnShouldChangeMoneyListener = mOnShouldChangeMoneyListener;    }    @Override    public int getGroupCount() {        return groups.size();    }    @Override    public int getChildrenCount(int i) {        return groups.get(i).getChildren().size();    }    @Override    public Object getGroup(int i) {        return groups.get(i);    }    @Override    public Object getChild(int i, int i1) {        return groups.get(i).getChildren().get(i1);    }    @Override    public long getGroupId(int i) {        return i;    }    @Override    public long getChildId(int i, int i1) {        return i1;    }    @Override    public boolean hasStableIds() {        return false;    }    @Override    public View getGroupView(final int i, boolean b, View view, ViewGroup viewGroup) {        GroupHolder holder = null;        if (view == null){            view = LayoutInflater.from(context).inflate(R.layout.group_item,viewGroup,false);            holder  = new GroupHolder();            holder.checkBox = (CheckBox) view.findViewById(R.id.group_check);            view.setTag(holder);        }else{            holder = (GroupHolder) view.getTag();        }        holder.checkBox.setText(groups.get(i).getName());        holder.checkBox.setChecked(groups.get(i).isCheck());        if (mOnCheckChangeListener != null&&mOnShouldChangeMoneyListener != null){            holder.checkBox.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    mOnCheckChangeListener.onGroupClick(i);                    mOnShouldChangeMoneyListener.onShouldChnageMoney();                }            });        }        return view;    }    @Override    public View getChildView(final int i,final int i1, boolean b, View view, ViewGroup viewGroup) {        ChildHolder holder = null;        if (view == null){            view = LayoutInflater.from(context).inflate(R.layout.child_item,viewGroup,false);            holder = new ChildHolder();            holder.checkBox = (CheckBox) view.findViewById(R.id.child_check);            holder.imageView = (ImageView) view.findViewById(R.id.child_img);            holder.name = (TextView) view.findViewById(R.id.child_name);            holder.num = (TextView) view.findViewById(R.id.child_num);            holder.jian = (TextView) view.findViewById(R.id.child_jian);            holder.jia = (TextView) view.findViewById(R.id.child_jia);            holder.price = (TextView) view.findViewById(R.id.child_price);            view.setTag(holder);        }else{            holder = (ChildHolder) view.getTag();        }        holder.checkBox.setChecked(groups.get(i).getChildren().get(i1).isCheck());        holder.imageView.setImageResource(R.mipmap.ic_launcher);        holder.name.setText(groups.get(i).getChildren().get(i1).getName());        holder.num.setText(groups.get(i).getChildren().get(i1).getNum()+"");        holder.price.setText(groups.get(i).getChildren().get(i1).getPrice()+"");        if (mOnNumChangeListener != null&&mOnShouldChangeMoneyListener != null){            holder.jian.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    mOnNumChangeListener.onNumChange(i,i1,false);                    mOnShouldChangeMoneyListener.onShouldChnageMoney();                }            });        }        if (mOnNumChangeListener != null&&mOnShouldChangeMoneyListener != null){            holder.jia.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    mOnNumChangeListener.onNumChange(i,i1,true);                    mOnShouldChangeMoneyListener.onShouldChnageMoney();                }            });        }        if (mOnCheckChangeListener != null&&mOnShouldChangeMoneyListener != null){            holder.checkBox.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    mOnCheckChangeListener.onChildClick(i,i1);                    mOnShouldChangeMoneyListener.onShouldChnageMoney();                }            });        }        return view;    }    @Override    public boolean isChildSelectable(int i, int i1) {        return true;    }    class GroupHolder {        CheckBox checkBox;    }    class ChildHolder{        CheckBox checkBox;        ImageView imageView;        TextView name,num,jian,jia,price;    }}

MainActivity:

package com.bwie.test.test1025two;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.ExpandableListView;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {    TextView num,price;//右上角当前商品数量和底部当前已选中商品的价格    ExpandableListView expandableListView;//展示商品信息的二级列表    CheckBox checkAll;//左下角全选    Button btnDel,btnBuy;//底部删除当前选中按钮、购买按钮    ArrayList<Group> groups = new ArrayList<>();//数据源集合    MyAdapter adapter;//自定义baseExpandable适配器    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();//控件初始化        initData();//数据初始化        changeGoodsNum();//初始化当前商品个数。        /**         * 自定义加减按钮回调         * params: groupID:商铺id  childID:商品在当前商铺的id isADD:非加即减         */        adapter.setOnNumChangeListener(new MyAdapter.onNumChangeListener() {            @Override            public void onNumChange(int groupID, int childID, boolean isAdd) {                //获得当前点击商品的数量                int num = groups.get(groupID).getChildren().get(childID).getNum();                if (isAdd){//加                    //在数据源中该商品数量自增1                    groups.get(groupID).getChildren().get(childID).setNum(++num);                }else{//减                    if (num == 1){//数量为1给出提示                        Toast.makeText(MainActivity.this, "受不了了,不能再少了", Toast.LENGTH_SHORT).show();                    }else{//在数据源中该商品数量自减1                        groups.get(groupID).getChildren().get(childID).setNum(--num);                    }                }                //更新UI                adapter.notifyDataSetChanged();                changeMoney();//更新价格显示            }        });        //自定义商铺和商品多选框点击回调        adapter.setmOnCheckChangeListener(new MyAdapter.onCheckChangeListener() {            @Override            public void onGroupClick(int groupID) {//组点击                //将数据源置反,以保持同步                groups.get(groupID).setCheck(!(groups.get(groupID).isCheck()));                //获取当前选中状态                boolean flag = groups.get(groupID).isCheck();                //更新其下所有商品CheckBox                for (int i = 0 ; i < groups.get(groupID).getChildren().size(); i++){                    groups.get(groupID).getChildren().get(i).setCheck(flag);                }                //更新UI                adapter.notifyDataSetChanged();                //更新价格显示                changeMoney();            }            @Override            public void onChildClick(int groupID, int childID) {//商品点击                //将数据源置反以保持同步                groups.get(groupID).getChildren().get(childID).setCheck(!(groups.get(groupID).getChildren().get(childID).isCheck()));                //判断该条目及所有兄弟条目是否全部选中,以及时更新商铺CheckBox                int flag = 0;                for (int i = 0 ; i < groups.get(groupID).getChildren().size() ; i++){                    if (groups.get(groupID).getChildren().get(i).isCheck()){                        flag++;                    }                }                //如果该组下的选中数量与该集合长度相等,说明全部选中,更新组CheckBox                if (flag == groups.get(groupID).getChildren().size()){                    groups.get(groupID).setCheck(true);                }else{                    groups.get(groupID).setCheck(false);                }                //更新UI                adapter.notifyDataSetChanged();                //更新价格显示                changeMoney();            }        });        //删除按钮点击        btnDel.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                List<Group> toBeDeleteGroups = new ArrayList<Group>();// 待删除的组元素列表                for (int i = 0; i < groups.size(); i++) {                    Group group = groups.get(i);                    if (group.isCheck()) {                        toBeDeleteGroups.add(group);                    }                    List<Child> toBeDeleteChildren = new ArrayList<Child>();// 待删除的子元素列表                    List<Child> childs = group.getChildren();                    for (int j = 0; j < childs.size(); j++) {                        if (childs.get(j).isCheck()) {                            toBeDeleteChildren.add(childs.get(j));                        }                    }                    childs.removeAll(toBeDeleteChildren);                }                groups.removeAll(toBeDeleteGroups);                //更新UI                adapter.notifyDataSetChanged();                //更新当前商品数量显示                changeGoodsNum();                //更新当前价格显示                changeMoney();            }        });        //购买按钮,点击提示当前选中金额        btnBuy.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                String money = price.getText().toString();                Toast.makeText(MainActivity.this, "当前总金额:"+money, Toast.LENGTH_SHORT).show();            }        });        //全选按钮,点击更新视图所有CheckBox        checkAll.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                for (int i = 0 ; i< groups.size() ; i++){                    groups.get(i).setCheck(checkAll.isChecked());                    for (int j = 0 ; j < groups.get(i).getChildren().size() ; j ++){                        groups.get(i).getChildren().get(j).setCheck(checkAll.isChecked());                    }                }                //更新UI                adapter.notifyDataSetChanged();                //更新总价显示                changeMoney();            }        });        //自定义回调更新总价        adapter.setmOnShouldChangeMoneyListener(new MyAdapter.onShouldChangeMoneyListener() {            @Override            public void onShouldChnageMoney() {                //更新总价显示                changeMoney();            }        });    }    //初始化数据,设置适配器    private void initData() {        for (int i = 0 ; i < 5 ; i++){            ArrayList<Child> children = new ArrayList<>();            for (int j = 0 ; j <= i ; j++){                children.add(new Child("店铺"+i+"的商品:"+j,"",2,false,j+1));            }            groups.add(new Group("商铺:"+i,false,children));        }        adapter = new MyAdapter(this,groups);        expandableListView.setAdapter(adapter);        for (int i = 0; i < groups.size(); i++)        {            expandableListView.expandGroup(i);// 初始化时,将ExpandableListView以展开的方式呈现        }    }    //获得控件资源    private void initView() {        num = (TextView) findViewById(R.id.main_num);        expandableListView = (ExpandableListView) findViewById(R.id.expand_able_view);        checkAll = (CheckBox) findViewById(R.id.main_check_all);        btnDel = (Button) findViewById(R.id.btn_delete);        btnBuy = (Button) findViewById(R.id.btn_buy);        price = (TextView) findViewById(R.id.main_price);    }    //当前购物车商品数量    private void changeGoodsNum(){        int currentNum = 0;        for (int i = 0 ; i < groups.size(); i++){            for (int j = 0 ; j < groups.get(i).getChildren().size(); j++){                currentNum++;            }        }        num.setText(currentNum+"");    }    //更新总价    private void changeMoney(){        int money = 0;        int allMoney = 0;//获得当前全部商品价格        for (int i = 0 ; i < groups.size(); i++){            for (int j = 0 ; j < groups.get(i).getChildren().size(); j++){                if (groups.get(i).getChildren().get(j).isCheck()){                    money += groups.get(i).getChildren().get(j).getNum() * groups.get(i).getChildren().get(j).getPrice();                }                allMoney += groups.get(i).getChildren().get(j).getNum() * groups.get(i).getChildren().get(j).getPrice();            }        }        //当选中价格与全部价格相等,更新全选框        if (money == allMoney){            checkAll.setChecked(true);        }else{            checkAll.setChecked(false);        }        price.setText(money + "");    }}

效果图:


原创粉丝点击