ExpandableListView二级列表的基本使用(购物车)

                   

以上是效果图   

        主要实现的功能: 二级列表的展示   ExpandableListView     (加减数量的 功能使用自定义View组合控件实现)

实现复选框的联动,底部的全选,反选,     列表内,分组与成员之间的联动     

请求数据使用MVP+OkHttp3实现,在上一篇博客里已有代码,这里就不上传了,

个人做的时候是用到什么方法定义什么方法的,顺着功能实现的步骤写的

接下来是具体实现过程,以及逻辑,具体的注释在代码里以经标明,这里就是大概的过程

///、首先

在清单文件中添加权限,  这里用到了网络权限

<uses-permission android:name="android.permission.INTERNET"/>

//要导入的依赖

    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'com.android.support:design:28.0.0'
    implementation 'com.squareup.okhttp3:okhttp:3.12.0'
    implementation 'com.github.bumptech.glide:glide:4.8.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'

//接下来是布局文件,以及自定义View

//主页面布局      -    二级列表  组布局   子布局    -   自定义Veiw  布局    ,自定义View 布局添加在子布局中

//主页面布局--activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/Lin"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#ccc"
        android:gravity="center_vertical"
        android:orientation="horizontal">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1">
            <CheckBox
                android:id="@+id/CheckAll"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="全选"/>
        </LinearLayout>
        <TextView
            android:id="@+id/Price_Sum"
            android:layout_width="wrap_content"
            android:layout_weight="1"
            android:textSize="24sp"
            android:layout_height="wrap_content"
            android:text="总价"/>
        <TextView
            android:id="@+id/Close_Sum"
            android:layout_width="wrap_content"
            android:layout_weight="1"
            android:textSize="24sp"
            android:layout_height="wrap_content"
            android:text="结算"/>
    </LinearLayout>
    <ExpandableListView
        android:id="@+id/Expandable_View"
        android:layout_above="@id/Lin"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </ExpandableListView>

</RelativeLayout>

//二级列表布局   组布局与子布局

组布局  groupview.xml

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

子布局 childview.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="20dp">
        <CheckBox
            android:id="@+id/Child_Box"
            android:layout_centerVertical="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    <ImageView
        android:id="@+id/Child_Img"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@id/Child_Box"
        android:src="@mipmap/ic_launcher"/>
    <LinearLayout
        android:id="@+id/lin"
        android:layout_width="wrap_content"
        android:layout_centerVertical="true"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/Child_Img"
        android:orientation="vertical">
        <TextView
            android:id="@+id/Child_Name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="名字"/>
        <TextView
            android:id="@+id/Child_Price"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="价格"/>
    </LinearLayout>
    <com.example.shopdemo1.weight.Add_Delete_View
        android:layout_alignParentRight="true"
        android:id="@+id/Add_Delete_View"
        android:layout_centerVertical="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </com.example.shopdemo1.weight.Add_Delete_View>
</RelativeLayout>

//自定义View布局以及Java代码

布局add_delete.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#000"
    android:layout_margin="3dp"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/Delete"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="#fff"
        android:layout_margin="1dp"
        android:textSize="24sp"
        android:gravity="center"
        android:text="--"/>
    <TextView
        android:id="@+id/Number"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="#fff"
        android:layout_margin="1dp"
        android:textSize="24sp"
        android:gravity="center"
        android:text="0"/>
    <TextView
        android:id="@+id/Add"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="#fff"
        android:layout_margin="1dp"
        android:textSize="24sp"
        android:gravity="center"
        android:text="+"/>
</LinearLayout>

//Java代码 Add_Delete_View    这里要与后面的代码有联动所以有接口回调

package com.example.shopdemo1.weight;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.shopdemo1.R;

/*
* 自定义view组合控件    加+ 减-
* */
public class Add_Delete_View extends LinearLayout implements View.OnClickListener {

    private TextView mAdd,mDelete,mNumber;
    //初始化计数
    private int counts;
    public Add_Delete_View(Context context, AttributeSet attrs) {
        super(context, attrs);
        //加载布局
        LayoutInflater.from(context).inflate(R.layout.add_delete,this);
        //加载控件
        initView();
    }

    private void initView() {
        mAdd = findViewById(R.id.Add);
        mDelete=findViewById(R.id.Delete);
        mNumber=findViewById(R.id.Number);
        //注册点击的监听事件
        mAdd.setOnClickListener(this);
        mDelete.setOnClickListener(this);
    }

    //先给初始化赋值
    public void setNumber(int number) {
        this.counts = number;
        mNumber.setText(number + "");
    }

    //点击监听事件
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.Add:
                //点击添加数量
                counts++;
                mNumber.setText( counts+"");
                //通过接口设置值
                if (monCountChange!=null){
                    monCountChange.setNumber(counts);
                }
                break;
            case R.id.Delete:
                //点击减少数量   判断数量是否为零
                if (counts>0){
                    counts--;
                    mNumber.setText(counts+"");
                    //通过接口设置值
                    if (monCountChange!=null){
                        monCountChange.setNumber(counts);
                    }
                }else{
                    Toast.makeText(getContext(),"请添加购买数量",Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    //因为在适配器和Activity中要用到加和减的功能,通过接口回调完成
    //自定义接口
    public interface OnCountChange{
        //定义一个方法
        void setNumber(int count);
    }
    //实例化
    private OnCountChange monCountChange;
    //方法
    public void setOnChange(OnCountChange onChange){
        this.monCountChange=onChange;
    }
}

//接下来,要写的东西是网络请求工具类,以及Mvp模式的搭建,这里就不写了,在之前的博客里有,

 

//接下来是最重要的部分  二级列表的适配器  以及  MainActivtty 

建议两个类结合起来看,明白适配器里的接口,在activity里的调用

我习惯从activity里来看,方便找到调用的方法,具体的功能以及写在了代码里

先是适配器,需要在里面先写好回调的接口,以及要调用的方法  在最下面

package com.example.shopdemo1.adapter;

import android.content.Context;
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 com.bumptech.glide.Glide;
import com.example.shopdemo1.R;
import com.example.shopdemo1.bean.GoodsBean;
import com.example.shopdemo1.weight.Add_Delete_View;

import java.util.ArrayList;
import java.util.List;

/*
* 适配器
* */
public class MyAdapter extends BaseExpandableListAdapter {
    private Context mContext;
    private ArrayList<GoodsBean.DataBean>mData;

    public MyAdapter(Context mContext, ArrayList<GoodsBean.DataBean> mData) {
        this.mContext = mContext;
        this.mData = mData;
    }

    //组布局的数量
    @Override
    public int getGroupCount() {
        return mData.size();
    }

    //子布局的数量
    @Override
    public int getChildrenCount(int groupPosition) {
        return mData.get(groupPosition).getSpus().size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return null;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return null;
    }

    @Override
    public long getGroupId(int groupPosition) {
        return 0;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return 0;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    //组布局的视图
    @Override
    public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        GroupHoudler groupHoudler=null;
        if (convertView==null){
            groupHoudler=new GroupHoudler();
            convertView=View.inflate(mContext, R.layout.groupview,null);
            groupHoudler.groupCheckbox=convertView.findViewById(R.id.Group_Box);
            groupHoudler.groupName=convertView.findViewById(R.id.Group_Name);
            convertView.setTag(groupHoudler);
        }else{
            groupHoudler= (GroupHoudler) convertView.getTag();
        }
        GoodsBean.DataBean dataBean = mData.get(groupPosition);
        groupHoudler.groupName.setText(dataBean.getName()+"");
        //通过方法判断子布局是否都选中
        final boolean childCheckedAll =isChildAllCheck(groupPosition);
        groupHoudler.groupCheckbox.setChecked(childCheckedAll);
        //设置监听事件
        groupHoudler.groupCheckbox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (adaptercallback!=null){
                    adaptercallback.setGroupCheck(groupPosition);
                }
            }
        });
        return convertView;
    }

    //子布局的视图
    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        ChildHoudle childHoudle=null;
        if (convertView==null){
            childHoudle=new ChildHoudle();
            convertView=View.inflate(mContext, R.layout.childview,null);
            childHoudle.childCheckbox=convertView.findViewById(R.id.Child_Box);
            childHoudle.childImage=convertView.findViewById(R.id.Child_Img);
            childHoudle.childName=convertView.findViewById(R.id.Child_Name);
            childHoudle.childPrice=convertView.findViewById(R.id.Child_Price);
            childHoudle.add_delete_view=convertView.findViewById(R.id.Add_Delete_View);
            convertView.setTag(childHoudle);
        }else{
            childHoudle= (ChildHoudle) convertView.getTag();
        }
        GoodsBean.DataBean.SpusBean spusBean = mData.get(groupPosition).getSpus().get(childPosition);
        childHoudle.childCheckbox.setChecked(spusBean.isChildChecked());
        Glide.with(mContext).load(spusBean.getPic_url()).into(childHoudle.childImage);
        childHoudle.childName.setText(spusBean.getName());
        childHoudle.childPrice.setText("¥:"+spusBean.getSkus().get(0).getPrice());
        //给自定义view赋值
        childHoudle.add_delete_view.setNumber(spusBean.getPraise_num());

        //复选框的联动
        childHoudle.childCheckbox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (adaptercallback!=null){
                    adaptercallback.setChlidCheck(groupPosition,childPosition);
                }
            }
        });
        //调用自定义View,动态改变数量
        childHoudle.add_delete_view.setOnChange(new Add_Delete_View.OnCountChange() {
            @Override
            public void setNumber(int count) {
                if (adaptercallback!=null){
                    adaptercallback.setNumber(groupPosition,childPosition,count);
                }
            }
        });

        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }

    //判断子布局是否全部被选中
    public boolean isChildAllCheck(int groupPosition) {
        //初始花一个boolean变量
        boolean boo=true;
        //获取每个子布局中的复选框的状态   首先获取到复选框所在的集合
        GoodsBean.DataBean dataBean = mData.get(groupPosition);
        List<GoodsBean.DataBean.SpusBean> spus = dataBean.getSpus();
        //循环遍历
        for (int i = 0; i < spus.size(); i++) {
            //获取集合中的每一个元素
            GoodsBean.DataBean.SpusBean spusBean = spus.get(i);
            //判断复选框标识的状态   如果为选中状态跳过判断继续循环,如果未选中则返回false
            if (!spusBean.isChildChecked()){
                return false;
            }
        }
        return boo;
    }

    //点击组复选框让旗下所有子布局选中
    public void childAllCheck(int groupPosition, boolean isCheck) {
        GoodsBean.DataBean dataBean = mData.get(groupPosition);
        List<GoodsBean.DataBean.SpusBean> spus = dataBean.getSpus();
        //循环遍历
        for (int i = 0; i < spus.size(); i++) {
            //获取集合中的每一个元素
            GoodsBean.DataBean.SpusBean spusBean = spus.get(i);
            //将子布局中的复选框选中
            spusBean.setChildChecked(isCheck);
        }
    }

    //查看子布局中的商品是否被选中
    public boolean isChildAllChecked(int groupPosition, int childPosition) {
        //获取当前的子集合  并返回当前的状态
        GoodsBean.DataBean.SpusBean spusBean = mData.get(groupPosition).getSpus().get(childPosition);
        if (spusBean.isChildChecked()){
            return true;
        }
        return false;
    }

    //点击给他赋值   切换状态
    public void setChildChecked(int groupPosition, int childPosition, boolean b) {
        GoodsBean.DataBean.SpusBean spusBean = mData.get(groupPosition).getSpus().get(childPosition);
        spusBean.setChildChecked(b);
    }

    //判断集合中的所有元素,如果都选中,则返回一个true,否则返回一个true
    public boolean isAllGoods() {
        //初始化一个变量
        boolean boos=true;
        //循环嵌套,遍历所有数据
        for (int i = 0; i <mData.size() ; i++) {
            GoodsBean.DataBean dataBean = mData.get(i);
            for (int j = 0; j < dataBean.getSpus().size(); j++) {
                GoodsBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
                //只要有一个未选中就返回false
                if (!spusBean.isChildChecked()){
                    boos=false;
                }
            }
        }
        return boos;
    }

    //全选反选
    public void setAllGoodsIsChecked(boolean b) {
        //给所有的元素复选框赋值
        for (int i = 0; i <mData.size() ; i++) {
            GoodsBean.DataBean dataBean = mData.get(i);
            for (int j = 0; j < dataBean.getSpus().size(); j++) {
                GoodsBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
                //只要有一个未选中就返回false
                spusBean.setChildChecked(b);
            }
        }
    }

    //设置数量以及价格
    public void setShopnumber(int groupPosition, int childPosition, int number) {
        GoodsBean.DataBean.SpusBean spusBean = mData.get(groupPosition).getSpus().get(childPosition);
        spusBean.setPraise_num(number);
    }

    //获取选中的商品价格总价
    public float getAllGoodsPrice() {
        float allPrice = 0;
        for (int i = 0; i < mData.size(); i++) {
            GoodsBean.DataBean dataBean = mData.get(i);
            for (int j = 0; j < dataBean.getSpus().size(); j++) {
                GoodsBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
                if (spusBean.isChildChecked()){
                    allPrice = allPrice + spusBean.getPraise_num() * Float.parseFloat(spusBean.getSkus().get(0).getPrice());
                }
            }
        }
        return allPrice;
    }

    //或者选中的商品数量
    public int getAllGoodsNumber() {
        int allNumber = 0;
        for (int i = 0; i < mData.size(); i++) {
            GoodsBean.DataBean dataBean = mData.get(i);
            for (int j = 0; j < dataBean.getSpus().size(); j++) {
                GoodsBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
                if (spusBean.isChildChecked()){
                    allNumber = allNumber + spusBean.getPraise_num();
                }
            }
        }
        return allNumber;
    }

    class GroupHoudler{
        private CheckBox groupCheckbox;
        private TextView groupName;
    }
    class ChildHoudle{
        private CheckBox childCheckbox;
        private ImageView childImage;
        private TextView childName;
        private TextView childPrice;
        private Add_Delete_View add_delete_view;
    }

    //定义接口,接口回调
    public interface Adaptercallback{
        void setGroupCheck(int groupPosition);
        void setChlidCheck(int groupPosition,int childPosition);
        void setNumber(int groupPosition, int childPosition, int number);
    }
    //实例化
    private Adaptercallback adaptercallback;

    //设置回调的数据
    public void setCallback(Adaptercallback adaptercallback) {
        this.adaptercallback = adaptercallback;
    }
}

//Activity.这里调用P层,以及回调的接口,请求数据,   然后通过适配器调用适配器里的接口方法实现功能的联动

package com.example.shopdemo1;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.shopdemo1.adapter.MyAdapter;
import com.example.shopdemo1.bean.GoodsBean;
import com.example.shopdemo1.presenter.PresenterImpl;
import com.example.shopdemo1.view.Iview;

import java.util.ArrayList;

public class MainActivity<T> extends AppCompatActivity implements Iview<T> {
    //网址
    private String mUrl="http://www.wanandroid.com/tools/mockapi/6523/restaurant-list";
    //集合
    private ArrayList<GoodsBean.DataBean> mList=new ArrayList<>();
    private CheckBox mCheckAll;
    private ExpandableListView mExpand;
    private TextView mPriceSum;
    private TextView mCloseSum;
    private PresenterImpl presenter;
    private MyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //查找组件
        initView();
        //调用P层   请求数据
        presenter = new PresenterImpl(this);
        presenter.StartRequestX(mUrl);
        adapter = new MyAdapter(this, mList);
        mExpand.setAdapter(adapter);

        //通过接口调用适配器的方法   完成复选框的联动,以及数值的变更
        adapter.setCallback(new MyAdapter.Adaptercallback() {
            //组布局    实现功能,点击复选框,该组中的商品全部选中,反之亦然,
            @Override
            public void setGroupCheck(int groupPosition) {
                //1.判断复选框中的子布局是否全部被选中
                boolean childAllCheck=adapter.isChildAllCheck(groupPosition);
                //操作,点击组,让所有的子布局中的复选框都被选中
                adapter.childAllCheck(groupPosition, !childAllCheck);
                //刷新适配器
                adapter.notifyDataSetChanged();
                flushBottomLayout();
            }
            //子布局
            @Override
            public void setChlidCheck(int groupPosition, int childPosition) {
                //1.获取当前商品的状态
                boolean childChecked=adapter.isChildAllChecked(groupPosition,childPosition);
                //点击操作,选中当前商品的布局
                adapter.setChildChecked(groupPosition,childPosition,!childChecked);
                adapter.notifyDataSetChanged();
                flushBottomLayout();

            }
            //数值   设置数量    设置 价格
            @Override
            public void setNumber(int groupPosition, int childPosition, int number) {
                adapter.setShopnumber(groupPosition,childPosition,number);
                adapter.notifyDataSetChanged();
                flushBottomLayout();
            }
        });
        //全选,反选的点击事件
        mCheckAll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //获取当前状态
                boolean allGoods = adapter.isAllGoods();
                //重新赋值
                adapter.setAllGoodsIsChecked(!allGoods);
                //刷新适配器
                adapter.notifyDataSetChanged();
                flushBottomLayout();
            }
        });
    }

    //刷新底部数据
    private void flushBottomLayout() {
        boolean allGoods = adapter.isAllGoods();
        mCheckAll.setChecked(allGoods);
        //获取选中商品的价格
        float allGoodsPrice = adapter.getAllGoodsPrice();
        //获取选中商品的数量
        int allGoodsNumber = adapter.getAllGoodsNumber();
        mPriceSum.setText("价格:" + allGoodsPrice);
        mCloseSum.setText("去结算(" + allGoodsNumber + ")");
    }

    private void initView() {
        //复选框,二级列表,textview
        mCheckAll = findViewById(R.id.CheckAll);
        mExpand = findViewById(R.id.Expandable_View);
        mPriceSum = findViewById(R.id.Price_Sum);
        mCloseSum = findViewById(R.id.Close_Sum);
        //去掉小三角
        mExpand.setGroupIndicator(null);
    }

    //成功
    @Override
    public void success(T data) {
        GoodsBean goodsBean= (GoodsBean) data;
        //将网络请求到的数据添加到集合中
        mList.addAll(goodsBean.getData());
        adapter.notifyDataSetChanged();
    }

    //失败
    @Override
    public void error(T error) {
        Toast.makeText(this,error+"",Toast.LENGTH_SHORT).show();
    }


}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值