本文实例为大家分享了Android实现简单购物车的具体代码,供大家参考,具体内容如下
这里我用到的都是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 + "");
}
}
效果图: