二级列表实现购物车,使用OkHttpClient请求数据

二级列表做购物车最难的就是关联,需要判断,逻辑比较绕,但只要自己好好看看,理解理解还是会感到很简单的。

先看效果,再说代码

在这里插入图片描述
在这里插入图片描述
如果要把所有的不同都上传就太多了,所有这里就先放3张图片

在做功能之前,我们应该先把要使用的依赖导入,权限加上

    //因为我们要从网上获取数据,所以导入okhttp,然后用gson解析,用glide加载图片
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'com.squareup.okhttp3:okhttp:3.12.0'
    implementation 'com.github.bumptech.glide:glide:4.8.0'

然后在清单文件中添加权限

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

现在先写activity.xml文件

<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/send_footer"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">

        <CheckBox
            android:id="@+id/send_all"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:focusable="false"
            android:text="全选"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/send_price"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:gravity="center"
            android:text="价格:0.0"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/send_sum"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:gravity="center"
            android:text="总数量:0"
            android:textSize="20sp" />
    </LinearLayout>

    <ExpandableListView
        android:id="@+id/send_expand"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/send_footer"></ExpandableListView>
</RelativeLayout>

一级的xml文件视图

<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_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="false"
        android:textSize="35sp" />

    <TextView
        android:id="@+id/group_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="35sp" />

</LinearLayout>

二级的xml文件的视图

<RelativeLayout 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"
        android:textSize="25sp" />

    <ImageView
        android:id="@+id/child_image"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_toRightOf="@id/child_check" />

    <TextView
        android:id="@+id/child_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/child_image"
        android:textSize="25sp" />

    <TextView
        android:id="@+id/child_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/child_title"
        android:textColor="#f00"
        android:textSize="25sp" />
     //自定义的控件
    <com.bwie.lian.weight.MyView
        android:id="@+id/child_myview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/child_title"
        android:layout_toRightOf="@id/child_image"></com.bwie.lian.weight.MyView>
</RelativeLayout>

在这里有一个自定义的控件

在自定义之前要有一个xml文件,里面有两张图片,可以用自己的来替换。它的效果如下:

在这里插入图片描述

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/send_jia"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/jia" />

    <TextView
        android:id="@+id/send_number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="0"
        android:textSize="35sp" />

    <ImageView
        android:id="@+id/send_jian"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/jian" />
</LinearLayout>

现在就应该写一个类,来自定义

public class MyView extends LinearLayout implements View.OnClickListener {
    private ImageView send_jia;
    private TextView send_number;
    private ImageView send_jian;
    private int mNumber;
    private Context mContext;

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        //获取视图
        LayoutInflater.from(context).inflate(R.layout.number_list, this);
        //查找控件
        initView();
    }
  
  //定义一个方法来获取商品数量
    public void setChildNumber(int number) {
        this.mNumber = number;
        send_number.setText("数量是:" + mNumber);
    }

    private void initView() {
        send_jia = findViewById(R.id.send_jia);
        send_jia.setOnClickListener(this);
        send_number = findViewById(R.id.send_number);
        send_jian = findViewById(R.id.send_jian);
        send_jian.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
    //判断点击事件
        switch (view.getId()) {
            case R.id.send_jian:
            //减得时候数量要大于0
                if (mNumber > 0) {
                    mNumber--;
                    //给TextView赋值
                    send_number.setText("数量是:" + mNumber);
                    //判断接口是否为空
                    if (onChangeChildCount != null) {
                    //将改完的数量传入接口中
                        onChangeChildCount.getChildCount(mNumber);
                    }
                } else {
                //提示
                    Toast.makeText(mContext, "数量最小为0", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.send_jia:
            //跟减的意思一样
                mNumber++;
                send_number.setText("数量是:" + mNumber);
                if (onChangeChildCount != null) {
                    onChangeChildCount.getChildCount(mNumber);
                }
                break;
        }
    }

    //自定义接口
    public interface OnChangeChildCount {
        void getChildCount(int number);
    }

    private OnChangeChildCount onChangeChildCount;

    public void setOnChangeChildCount(OnChangeChildCount onChangeChildCount) {
        this.onChangeChildCount = onChangeChildCount;
    }
}

现在是MainActivity中的代码

public class MainActivity extends AppCompatActivity {
    //网络请求的数据存入集合中
    private List<ShopBean.DataBean> mdata = new ArrayList<>();
    private String mUrl = "http://www.wanandroid.com/tools/mockapi/6523/restaurant-list";
    private CheckBox send_all;
    private TextView send_price;
    private TextView send_sum;
    private ExpandableListView send_expand;
    private MyAdapter adapter;
    @SuppressLint("HandlerLeak")
    //使用handler,在里面解析字符串,重新赋值,刷新适配器
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            String jsonStr = (String) msg.obj;
            Gson gson = new Gson();
            ShopBean shopBean = gson.fromJson(jsonStr, ShopBean.class);
            mdata.addAll(shopBean.getData());
            adapter.notifyDataSetChanged();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //查找控件
        initView();
        //配置适配器
        adapter = new MyAdapter(mdata, MainActivity.this);
        send_expand.setAdapter(adapter);
        //网络请求数据
        getData();
        //实现适配器中的接口
        adapter.setAdapterAllCallBack(new MyAdapter.AdapterAllCallBack() {
           //group的checkbox点击事件
            @Override
            public void setGroupChecked(int groupPosition) {
               //判断组内的子成员的checkbox是否全部选中
                boolean childs = adapter.AllChildIsChecked(groupPosition);
                //如果是true,那再点击group的checkbox就是实现全不选,所有要!一下
                //如果是false,则于此想反
                adapter.setGroupChecked(groupPosition, !childs);
                //刷新适配器
                adapter.notifyDataSetChanged();
                //每次有所改变时,都要刷新一下底部视图
                FlushFooterLayout();
            }

            @Override
            public void setChildChecked(int groupPosition, int childPosition) {
                //判断当前子成员的checkbox是否选中
                boolean chlid = adapter.thisChildIsChecked(groupPosition, childPosition);
                 //如果是true,那再点击checkbox就是实现不选,所有要!一下
                //如果是false,则于此想反
                adapter.setChildChecked(groupPosition, childPosition, !chlid);
                //刷新适配器
                adapter.notifyDataSetChanged();
                //每次有所改变时,都要刷新一下底部视图
                FlushFooterLayout();
            }

            @Override
            public void setFooterNumber(int groupPosition, int childPosition, int number) {
                adapter.setShopCount(groupPosition, childPosition, number);
                //刷新适配器
                adapter.notifyDataSetChanged();
                //每次有所改变时,都要刷新一下底部视图
                FlushFooterLayout();
            }
        });

        send_all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //判断所有的商品是否全部选中
                boolean b = adapter.thisAllShopsIsChecked();
                //如果是true,那再点击checkbox就是实现全不选,所有要!一下
                //如果是false,则于此想反
                adapter.setAllShopsChecked(!b);
                //刷新适配器
                adapter.notifyDataSetChanged();
                //每次有所改变时,都要刷新一下底部视图
                FlushFooterLayout();
            }
        });
    }

    //刷新底部视图
    public void FlushFooterLayout() {
        //判断所有的商品是否全部选中,根据返回值给底部的checkbox设置上
        boolean b = adapter.thisAllShopsIsChecked();
        send_all.setChecked(b);
        //获取数量,价格,显示出来
        int allShopNumbers = adapter.getAllShopNumbers();
        float allShopPrices = adapter.getAllShopPrices();
        send_price.setText("总价格:¥" + allShopPrices);
        send_sum.setText("总数量:" + allShopNumbers);
    }


    //网络获取数据
    private void getData() {
        //这是异步的get请求方式
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().url(mUrl).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //将数据发送到handler中
                handler.sendMessage(handler.obtainMessage(1, response.body().string()));
            }
        });
    }

    //获取控件
    private void initView() {
        send_all = (CheckBox) findViewById(R.id.send_all);
        send_price = (TextView) findViewById(R.id.send_price);
        send_sum = (TextView) findViewById(R.id.send_sum);
        send_expand = (ExpandableListView) findViewById(R.id.send_expand);
        send_expand.setGroupIndicator(null);
    }
}

然后是适配器中的内容

二级列表的适配器要继承BaseExpandableListAdapter并重写方法

public class MyAdapter extends BaseExpandableListAdapter {

    //用构造器传来数据和上下文
    private List<ShopBean.DataBean> data;
    private Context context;

    public MyAdapter(List<ShopBean.DataBean> data, Context context) {
        this.data = data;
        this.context = context;
    }

    //返回组的个数
    @Override
    public int getGroupCount() {
        return data.size();
    }
    //返回子成员的个数
    @Override
    public int getChildrenCount(int i) {
        return data.get(i).getSpus().size();
    }

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

    @Override
    public Object getChild(int i, int i1) {
        return null;
    }

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

    @Override
    public long getChildId(int i, int i1) {
        return 0;
    }

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

//组的视图,跟listview适配器中getview()方法写的东西一样
    @Override
    public View getGroupView(final int groupPosition, boolean b, View view, ViewGroup viewGroup) {
        GroupHolder holder = null;
        if (view == null) {
        //查找视图,控件
            view = View.inflate(context, R.layout.group_list, null);
            holder = new GroupHolder();
            holder.group_check = view.findViewById(R.id.group_check);
            holder.group_title = view.findViewById(R.id.group_title);
            view.setTag(holder);
        } else {
            holder = (GroupHolder) view.getTag();
        }
        //赋值
        holder.group_title.setText(data.get(groupPosition).getName());
        //调用方法AllChildIsChecked(groupPosition)来返回一个值,如果子成员全选中则为true,否则为false
        holder.group_check.setChecked(AllChildIsChecked(groupPosition));
        //checkbox的点击事件
        holder.group_check.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
            //判断是否为空
                if (adapterAllCallBack != null) {
                //为group的方法传入参数
                    adapterAllCallBack.setGroupChecked(groupPosition);
                }
            }
        });
        return view;
    }

    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean b, View view, ViewGroup viewGroup) {
        ChildHolder holder = null;
        if (view == null) {
            view = View.inflate(context, R.layout.child_list, null);
            holder = new ChildHolder();
            holder.child_check = view.findViewById(R.id.child_check);
            holder.child_image = view.findViewById(R.id.child_image);
            holder.child_title = view.findViewById(R.id.child_title);
            holder.child_price = view.findViewById(R.id.child_price);
            holder.child_myview = view.findViewById(R.id.child_myview);
            view.setTag(holder);
        } else {
            holder = (ChildHolder) view.getTag();
        }
       //glide加载图片
        Glide.with(context).load(data.get(groupPosition).getSpus().get(childPosition).getPic_url()).into(holder.child_image);
        //赋值
        holder.child_title.setText(data.get(groupPosition).getSpus().get(childPosition).getName());
        holder.child_price.setText("¥:" + data.get(groupPosition).getSpus().get(childPosition).getSkus().get(0).getPrice());
        holder.child_check.setChecked(data.get(groupPosition).getSpus().get(childPosition).isChildChecked());

//checkbox的点击事件
        holder.child_check.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (adapterAllCallBack != null) {
                //给child的方法传入参数
                    adapterAllCallBack.setChildChecked(groupPosition, childPosition);
                }
            }
        });


        
         //这是调用自定义控件的方法和接口        
         //将集合中的数量传入
             holder.child_myview.setChildNumber(data.get(groupPosition).getSpus().get(childPosition).getPraise_num());
             //控件的点击事件
        holder.child_myview.setOnChangeChildCount(new MyView.OnChangeChildCount() {
            @Override
            public void getChildCount(int number) {
                if (adapterAllCallBack != null) {
                //不为空时,传入参数
                    adapterAllCallBack.setFooterNumber(groupPosition, childPosition, number);
                }
            }
        });
        return view;
    }

    @Override
    public boolean isChildSelectable(int i, int i1) {
        return false;
    }
   //group
    class GroupHolder {
        CheckBox group_check;
        TextView group_title;
    }
  //child
    class ChildHolder {
        CheckBox child_check;
        ImageView child_image;
        TextView child_title;
        TextView child_price;
        MyView child_myview;
    }

    //点击组的checkbox,来实现全选,全不选
    public void setGroupChecked(int groupPosition, boolean childChecked) {
        List<ShopBean.DataBean.SpusBean> spus = data.get(groupPosition).getSpus();
        for (int i = 0; i < spus.size(); i++) {
            ShopBean.DataBean.SpusBean spusBean = spus.get(i);
            spusBean.setChildChecked(childChecked);
        }
    }

    //判断组内的child的checkbox是否选中
    public boolean AllChildIsChecked(int groupPosition) {
        List<ShopBean.DataBean.SpusBean> spus = data.get(groupPosition).getSpus();
        for (int i = 0; i < spus.size(); i++) {
            boolean childChecked = spus.get(i).isChildChecked();
            if (!childChecked) {
                return false;
            }
        }
        return true;
    }

    //根据已存在的状态,判断这次点击后的child中checkbox中状态
    public void setChildChecked(int groupPosition, int childPosition, boolean childChecked) {
        List<ShopBean.DataBean.SpusBean> spus = data.get(groupPosition).getSpus();
        for (int i = 0; i < spus.size(); i++) {
            ShopBean.DataBean.SpusBean spusBean = spus.get(childPosition);
            spusBean.setChildChecked(childChecked);
        }
    }

    //判断当前的child中的checkbox是否选中
    public boolean thisChildIsChecked(int groupPosition, int childPosition) {
        List<ShopBean.DataBean.SpusBean> spus = data.get(groupPosition).getSpus();
        for (int i = 0; i < spus.size(); i++) {
            ShopBean.DataBean.SpusBean spusBean = spus.get(childPosition);
            boolean childChecked = spusBean.isChildChecked();
            if (!childChecked) {
                return false;
            }
        }
        return true;
    }

    //根据判断,设置全选,全不选
    public void setAllShopsChecked(boolean childChecked) {
        for (int i = 0; i < data.size(); i++) {
            ShopBean.DataBean dataBean = data.get(i);
            for (int j = 0; j < dataBean.getSpus().size(); j++) {
                ShopBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
                spusBean.setChildChecked(childChecked);
            }
        }
    }

    //判断所有的商品是否选中
    public boolean thisAllShopsIsChecked() {
        for (int i = 0; i < data.size(); i++) {
            ShopBean.DataBean dataBean = data.get(i);
            for (int j = 0; j < dataBean.getSpus().size(); j++) {
                ShopBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
                if (!spusBean.isChildChecked()) {
                    return false;
                }
            }
        }
        return true;
    }

    //给商品数量赋值
    public void setShopCount(int groupPosition, int childPosition, int number) {
        data.get(groupPosition).getSpus().get(childPosition).setPraise_num(number);
    }

    //计算商品价格
    public float getAllShopPrices() {
        float mSum = 0;
        for (int i = 0; i < data.size(); i++) {
            ShopBean.DataBean dataBean = data.get(i);
            for (int j = 0; j < dataBean.getSpus().size(); j++) {
                ShopBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
                if (spusBean.isChildChecked()) {
                    mSum += spusBean.getPraise_num() * Float.parseFloat(spusBean.getSkus().get(0).getPrice());
                }
            }
        }
        return mSum;
    }

    //计算商品数量
    public int getAllShopNumbers() {
        int mSum = 0;
        for (int i = 0; i < data.size(); i++) {
            ShopBean.DataBean dataBean = data.get(i);
            for (int j = 0; j < dataBean.getSpus().size(); j++) {
                ShopBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
                if (spusBean.isChildChecked()) {
                    mSum += spusBean.getPraise_num();
                }
            }
        }
        return mSum;
    }

    //自定义接口
    public interface AdapterAllCallBack {
        //group点击时调用的方法
        void setGroupChecked(int groupPosition);
       //child点击时调用的方法
        void setChildChecked(int groupPosition, int childPosition);
       //自定义控件点击时调用的方法
        void setFooterNumber(int groupPosition, int childPosition, int number);
    }

    private AdapterAllCallBack adapterAllCallBack;

    public void setAdapterAllCallBack(AdapterAllCallBack adapterAllCallBack) {
        this.adapterAllCallBack = adapterAllCallBack;
    }
}

好了到现在,代码就写完了,虽然有点多,但也不要害怕,要一点一点理解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值