本篇博客来为大家讲解ExpandableListView(二级列表)来实现购物车,本人也是最近遇到了购物车的一些问题,进行一些总结。
购物车与正常的ExpandableListView的区别只不过是多了CheckBox,通过实现CheckBox的选中监听或者点击监听来改变状态去计算总价。
首先我们先来看一下购物车需要实现的逻辑(CheckBox相关)
1. 总开关(购物车布局中实现的一个CheckBox) —-> 全选/反选
2. 一级列表开关(一级列表的CheckBox) —–> 二级列表CheckBox的全选/反选
3. 当所有的一级列表的CheckBox都选中时,总开关被选中。
4. 只要有一个一级列表的CheckBox没有被选中,总开关也不会被选中。
5. 当前一级列表下所有的二级列表都被选中时,一级列表的CheckBox被选中
6. 只要当前一级列表下有一个二级列表没有被选中,一级列表的CheckBox不会被选中
7. 计算所有被选中的二级列表的价格(price*saleNum)
以上基本就是购物车的基本逻辑,可能看着有点懵,咱们来上图上代码
由于我不会制造gif动图,只能拿死图来看了,给看官道个歉。
1. 总开关(购物车布局中实现的一个CheckBox) —-> 全选/反选
//设置选中监听去实现全选
gouwuche_footer_check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b==true)
{
adapter.allCheck(true);
}
}
});
//设置点击监听去实现反选
gouwuche_footer_check.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//获取购物车的CheckBox的选中状态
boolean isCheck=gouwuche_footer_check.isChecked();
if(!isCheck)
{
adapter.allCheck(false);
}
}
});
/*adapter适配器中的方法*/
//全选
public void allCheck(boolean isCheck)
{
//通过遍历所有的集合,修改bean类来控制CheckBox的选中状态
for(int i=0;i<getGroupCount();i++)
{
ParentBean p=parentList.get(i);
p.isCheck=isCheck;
for(int a=0;a<getChildrenCount(i);a++)
{
ChildBean c=childList.get(i).get(a);
c.isCheck=isCheck;
}
}
//刷新适配器
notifyDataSetChanged();
}
为什么使用点击监听作为总开关控制反选的监听器?
如果使用选中监听实现反选的话,当我们的一级列表只要有一个不选中时,我们的总开关也不会被选中,这时会触发我们总开关的选中监听,使所有的CheckBox都变成未选中状态。
2. 一级列表开关(一级列表的CheckBox) —–> 二级列表CheckBox的全选/反选
//CheckBox添加选中监听器实现全选
list_1.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
ParentBean parentBean1= (ParentBean) list_11.checkBox.getTag();
parentBean1.isCheck=b;
//刷新适配器
notifyDataSetChanged();
}
});
//CheckBox添加点击监听器实现全选
list_1.checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
boolean isCheck=((CheckBox)view).isChecked();
if(!isCheck)
{
shopCheck(false,childList.get(i));
}
}
});
为什么使用点击监听作为一级列表开关控制反选的监听器?
原理同上
3. 当所有的一级列表的CheckBox都选中时,总开关被选中。
4. 只要有一个一级列表的CheckBox没有被选中,总开关也不会被选中。
private void allCheckChangeFromParent()
{
//遍历一级列表数据
for (ParentBean p:parentList)
{
//有一个未被选中,则全选按钮不会被选中
if(!p.isCheck)
{
iCartView.changeCheckBtn(false);
return;
}
}
//如果都被选中,则全选按钮选中
iCartView.changeCheckBtn(true);
}
//修改全选按钮的状态
@Override
public void changeCheckBtn(boolean flag) {
gouwuche_footer_check.setChecked(flag);
}
不懂接口回调的,先去百度一下接口回调怎么使用,当然,如果你是MVP框架模式的话,直接在你的View层中添加一个接口就可以了。
5. 当前一级列表下所有的二级列表都被选中时,一级列表的CheckBox被选中
6. 只要当前一级列表下有一个二级列表没有被选中,一级列表的CheckBox不会被选中
private void childCheck(int parentPosition)
{
//获取一级列表的bean 来修改isCheck属性
ParentBean parentBean=getGroup(parentPosition);
for(int i=0;i<getChildrenCount(parentPosition);i++)
{
//当前的Childbean
ChildBean bean=getChild(parentPosition,i);
if(!bean.isCheck)
{
parentBean.isCheck=false;
return;
}
parentBean.isCheck=true;
}
}
7. 计算所有被选中的二级列表的价格(price*saleNum)
//CheckBox添加监听器
list_2.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
//接口回调 调用计算总价的方法
iCartView.addPrice();
//刷新适配器
notifyDataSetChanged();
}
});
//计算总价的方法
@Override
public void addPrice() {
//初始化总价
sum=0;
//遍历所有的子集合
for(int i=0;i<adapter.getGroupCount();i++)
{
for (int j=0;j<adapter.getChildrenCount(i);j++)
{
ChildBean child=adapter.getChild(i,j);
//如果该对象被选中,则加上这个对象中的价钱
if(child.isCheck)
{
sum+=child.price*child.saleNum;
}
}
}
//得到总价,更新UI控件
gouwuche_footer_price.setText(sum+"");
}
同上,不懂接口回调的,先去百度一下接口回调怎么使用,当然,如果你是MVP框架模式的话,直接在你的View层中添加一个addPrice()接口就可以了。
ok,以上就是基本的购物车逻辑,其中还有一个比较重要的Bug要解决
当我的购物车数据超过屏幕显示范围后,并且我的适配器中采用了ViewHolder模式,导致超出显示范围的部分的数据不能正常的被更改
我的解决方式是利用我的CheckBox来绑定bean的数据,以后修改数据时,直接修改绑定后的bean类的数据,代码如下:
//利用我的CheckBox绑定数据
list_2.checkBox.setTag(childBean);
//下面是我获取数据,然后去修改数据的方式
ChildBean childBean1= (ChildBean) list_21.checkBox.getTag();
childBean1.isCheck=b;
当然我的购物车中还实现了编辑功能
编辑的功能我就不具体讲了,我的原理就是隐藏或者显示布局来控制编辑功能。
在bean类中多一个boolean值来控制显示或者隐藏。
下面是写的demo的代码
首先是xml布局
购物车的xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xp="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<xp.code.jd.view.TopBar
android:id="@+id/gouwuche_topbar"
android:layout_width="match_parent"
android:layout_height="60dp"
xp:rightImageSrc="@drawable/xx"
xp:title="购物车"
xp:titleColor="#000"
xp:titleSize="19dp">
</xp.code.jd.view.TopBar>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="@+id/gouwuche_footer"
android:layout_alignParentBottom="true">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:gravity="center_vertical"