1. 程式人生 > >購物車---二級列表---詳細註釋

購物車---二級列表---詳細註釋

activity_main

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <ExpandableListView
        android:id="@+id/ex_listView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="10" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal">

        <CheckBox
            android:id="@+id/all_box"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="全選" />

        <TextView
            android:id="@+id/all_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="總價:¥0.00"
            android:textSize="18sp" />

        <Button
            android:id="@+id/jiesuan_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="結算" />
    </LinearLayout>

</LinearLayout>

加減器 add_sub_item

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="80dp"
    android:layout_height="40dp"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/sub_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="-"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/num_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="1"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/add_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="+"
        android:textSize="20sp" />
</LinearLayout>

組佈局 parent_item

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="80dp"
    android:layout_height="40dp"
    android:orientation="horizontal">

    <CheckBox
        android:id="@+id/box_parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>

    <TextView
        android:id="@+id/text_parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="商家"
        android:textSize="20sp"
        android:layout_gravity="center"/>
</LinearLayout>

子佈局 child_item

<?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="120dp">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <CheckBox
            android:id="@+id/child_box"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"/>

        <ImageView
            android:id="@+id/child_image"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:padding="10dp"
            android:src="@mipmap/ic_launcher" />


    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_weight="1">

        <TextView
            android:id="@+id/child_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="15dp"
            android:text="jhsjhdsk"
            android:textSize="17sp" />

        <TextView
            android:id="@+id/child_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="10dp"
            android:text="¥0.0" />


    </LinearLayout>

    <wanghuiqi.bawie.com.whq_shop.view.MyAddSub
        android:id="@+id/add_sub"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical" />
</LinearLayout>

加減器 MyAddSub

package wanghuiqi.bawie.com.whq_shop.view;

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

import wanghuiqi.bawie.com.whq_shop.R;

public class MyAddSub extends LinearLayout implements View.OnClickListener {

    private TextView addText;
    private TextView subText;
    private TextView numText;
    private int number = 1;

    public MyAddSub(Context context) {
        this(context, null);
    }

    public MyAddSub(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyAddSub(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        View view = inflate(context, R.layout.add_sub_item, this);
        addText = view.findViewById(R.id.add_text);
        subText = view.findViewById(R.id.sub_text);
        numText = view.findViewById(R.id.num_text);

        addText.setOnClickListener(this);
        subText.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.add_text:
                ++number;
                numText.setText(number + "");
                if (mOnNumberChangeInterface != null) {
                    mOnNumberChangeInterface.onNumberChang(number);
                }
                break;
            case R.id.sub_text:
                //判斷如果數字比1大就減,比1小就吐司
                if (number > 1) {
                    --number;
                    numText.setText(number + "");
                    if (mOnNumberChangeInterface != null) {
                        mOnNumberChangeInterface.onNumberChang(number);
                    }
                } else {
                    Toast.makeText(getContext(), "不能再少了", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
        numText.setText(number + "");
    }

    //建立介面
    public interface OnNumberChangeInterface {
        void onNumberChang(int num);
    }

    //宣告介面名
    private OnNumberChangeInterface mOnNumberChangeInterface;

    //暴露方法
    public void setOnNumberChangeInterface(OnNumberChangeInterface onNumberChangeInterface) {
        mOnNumberChangeInterface = onNumberChangeInterface;
    }
}

adapter ShopAdapter

package wanghuiqi.bawie.com.whq_shop.adapter;

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.squareup.picasso.Picasso;

import java.util.List;

import wanghuiqi.bawie.com.whq_shop.R;
import wanghuiqi.bawie.com.whq_shop.model.bean.Shop;
import wanghuiqi.bawie.com.whq_shop.view.MyAddSub;

public class ShopAdapter extends BaseExpandableListAdapter {
    private List<Shop.DataBean> shopData;

    public ShopAdapter(List<Shop.DataBean> shopData) {
        this.shopData = shopData;
    }

    //1.有多少按鈕
    @Override
    public int getGroupCount() {
        return shopData.size();
    }

    //2.一個組裡有多少子條目
    @Override
    public int getChildrenCount(int groupPosition) {
        return shopData.get(groupPosition).getList().size();
    }


    ////////P.組佈局////////
    @Override
    public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        //P1.獲取組的下標
        Shop.DataBean dataBean = shopData.get(groupPosition);
        ParentHolder parentHolder;
        if (convertView == null) {
            convertView = View.inflate(parent.getContext(), R.layout.parent_item, null);
            parentHolder = new ParentHolder(convertView);
            convertView.setTag(parentHolder);
        } else {
            parentHolder = (ParentHolder) convertView.getTag();
        }
        //P2.獲取商家名稱
        parentHolder.textParent.setText(dataBean.getSellerName());
        //P3.根據當前商家的所有商品,確定checkbox是否選中
        boolean parentAllSelect = isParentAllSelect(groupPosition);
        //P4.1根據boolean判斷是否選中
        parentHolder.boxParent.setChecked(parentAllSelect);
        //P5.設定點選checkbox的點選事件,介面回撥
        parentHolder.boxParent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnCartListChangeListener != null) {
                    mOnCartListChangeListener.onParentCheckedChange(groupPosition);
                }
            }
        });
        return convertView;
    }


    ////////////C.子佈局///////////
    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        Shop.DataBean dataBean = shopData.get(groupPosition);
        List<Shop.DataBean.ListBean> list = dataBean.getList();
        //C1.拿到list集合裡具體商品
        Shop.DataBean.ListBean listBean = list.get(childPosition);
        ChildHolder childHolder;
        if (convertView == null) {
            convertView = View.inflate(parent.getContext(), R.layout.child_item, null);
            childHolder = new ChildHolder(convertView);
            convertView.setTag(childHolder);
        } else {
            childHolder = (ChildHolder) convertView.getTag();
        }
        //C2.擷取圖片picasso
        String images = listBean.getImages();
        String[] strings = images.split("!");
        Picasso.with(parent.getContext()).load(strings[0]).into(childHolder.imageChild);
        //C.獲取商品名稱
        childHolder.childText.setText(listBean.getTitle());
        //C.單價
        childHolder.childPrice.setText(listBean.getPrice() + "");
        //C.設定子條目複選框是否選中
        childHolder.boxChild.setChecked(listBean.getSelected() == 1);
        //C.設定加減器內部數量
        childHolder.addSub.setNumber(listBean.getNum());

        //C3.設定商品checkbox的點選事件,介面回撥
        childHolder.boxChild.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnCartListChangeListener != null) {
                    mOnCartListChangeListener.onChildCheckedChange(groupPosition, childPosition);
                }
            }
        });

        //C4.設定加減器的點選事件,介面回撥
        childHolder.addSub.setOnNumberChangeInterface(new MyAddSub.OnNumberChangeInterface() {
            @Override
            public void onNumberChang(int num) {
                if (mOnCartListChangeListener != null) {
                    mOnCartListChangeListener.onAddSubNumberChange(groupPosition, childPosition, num);
                }
            }
        });

        return convertView;
    }

    //--------判斷當前商品是否被選中--------
    public boolean isParentAllSelect(int groupPosition) {
        //拿到組的資料
        Shop.DataBean dataBean = shopData.get(groupPosition);
        //拿到商家所有商品,集合
        List<Shop.DataBean.ListBean> list = dataBean.getList();
        for (int i = 0; i < list.size(); i++) {
            //判斷這個組所有商品是否被選中,如有一個未選中就都不選中
            if (list.get(i).getSelected() == 0) {
                return false;
            }
        }
        return true;
    }

    //------底部全選按鈕邏輯判斷------
    public boolean isAllSelected() {
        for (int i = 0; i < shopData.size(); i++) {
            Shop.DataBean dataBean = shopData.get(i);
            List<Shop.DataBean.ListBean> list = dataBean.getList();
            for (int j = 0; j < list.size(); j++) {
                //判斷組的商品是否被選中
                if (list.get(j).getSelected() == 0) {
                    return false;
                }
            }
        }
        return true;
    }

    //-----計算商品總數量-----
    public int TotalNumber() {
        int totalNumber = 0;
        for (int i = 0; i < shopData.size(); i++) {
            Shop.DataBean dataBean = shopData.get(i);
            List<Shop.DataBean.ListBean> list = dataBean.getList();
            for (int j = 0; j < list.size(); j++) {
                //商品數量,選中的
                if (list.get(j).getSelected() == 1) {
                    //拿到商品的數量
                    int num = list.get(j).getNum();
                    totalNumber += num;
                }
            }
        }
        return totalNumber;
    }

    //-------計算商品總價格-------
    public float TotalPrice() {
        float totalPrice = 0;
        for (int i = 0; i < shopData.size(); i++) {
            Shop.DataBean dataBean = shopData.get(i);
            List<Shop.DataBean.ListBean> list = dataBean.getList();
            for (int j = 0; j < list.size(); j++) {
                //商品價格,選中的
                if (list.get(j).getSelected() == 1) {
                    //拿到商品數量
                    double price = list.get(j).getPrice();
                    int num = list.get(j).getNum();
                    totalPrice += price + num;
                }
            }
        }
        return totalPrice;
    }

    //--------根據選擇,更改選框裡狀態------
    public void changeSellerAllProduct(int groupPosition, boolean isSelected) {
        Shop.DataBean dataBean = shopData.get(groupPosition);
        List<Shop.DataBean.ListBean> list = dataBean.getList();
        for (int i = 0; i < list.size(); i++) {
            Shop.DataBean.ListBean listBean = list.get(i);
            listBean.setSelected(isSelected ? 1 : 0);
        }
    }

    //---------當子條目選中,更新組選框的狀態-------
    public void changeChild(int groupPosition, int childPosition) {
        Shop.DataBean dataBean = shopData.get(groupPosition);
        List<Shop.DataBean.ListBean> list = dataBean.getList();
        Shop.DataBean.ListBean listBean = list.get(childPosition);
        listBean.setSelected(listBean.getSelected() == 0 ? 1 : 0);
    }

    //---------當最底部全選框選中,更新所有選框的狀態
    public void changAllCheckBox(boolean selected) {
        for (int i = 0; i < shopData.size(); i++) {
            Shop.DataBean dataBean = shopData.get(i);
            List<Shop.DataBean.ListBean> list = dataBean.getList();
            for (int j = 0; j < list.size(); j++) {
                list.get(j).setSelected(selected ? 1 : 0);
            }
        }
    }
    //----------當加減器被點選時,改變商品數量--------
    public void changProductNumber(int groupPosition, int childPosition, int number){
        Shop.DataBean dataBean = shopData.get(groupPosition);
        List<Shop.DataBean.ListBean> list = dataBean.getList();
        Shop.DataBean.ListBean listBean = list.get(childPosition);
        listBean.setNum(number);
    }

    //==============Viewhodler============
    //組的Viewholder
    public static class ParentHolder {

        private final CheckBox boxParent;
        private final TextView textParent;

        public ParentHolder(View rootView) {
            boxParent = rootView.findViewById(R.id.box_parent);
            textParent = rootView.findViewById(R.id.text_parent);
        }
    }

    public static class ChildHolder {

        private final CheckBox boxChild;
        private final ImageView imageChild;
        private final TextView childText;
        private final TextView childPrice;
        private final MyAddSub addSub;

        public ChildHolder(View rootView) {
            boxChild = rootView.findViewById(R.id.child_box);
            imageChild = rootView.findViewById(R.id.child_image);
            childText = rootView.findViewById(R.id.child_text);
            childPrice = rootView.findViewById(R.id.child_price);
            addSub = rootView.findViewById(R.id.add_sub);
        }
    }

    //=============建立介面===========
    public interface onCartListChangeListener {
        /*當組的checkbox點選時回撥*/
        void onParentCheckedChange(int groupPosition);

        /*當點選子條目商品的checkbox回撥*/
        void onChildCheckedChange(int groupPosition, int childPosition);

        /*當點選加減按鈕的回撥*/
        void onAddSubNumberChange(int groupPosition, int childPosition, int number);
    }

    private onCartListChangeListener mOnCartListChangeListener;

    public void setOnCartListChangeListener(onCartListChangeListener onCartListChangeListener) {
        mOnCartListChangeListener = onCartListChangeListener;
    }

    //不管這些
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }

    @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;
    }
}

工具類 HttpUtils

package wanghuiqi.bawie.com.whq_shop.model;

import android.os.Handler;
import android.os.Looper;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class HttpUtils {

    private final Handler handler;
    private final OkHttpClient httpClient;
    private static HttpUtils mHttpUtils;

    private HttpUtils(){
        //建立主執行緒的handler
        handler = new Handler(Looper.getMainLooper());
        httpClient = new OkHttpClient.Builder()
                .connectTimeout(500, TimeUnit.MILLISECONDS)
                .readTimeout(5000, TimeUnit.MILLISECONDS)
                .writeTimeout(5000, TimeUnit.MILLISECONDS)
                .build();
    }
    //建立介面
    public interface OKhttpInterface{
        void Failed(Exception e);
        void Success(String data);
    }
    public void doGet(String url, final OKhttpInterface mOkhttpInterface){
        Request request = new Request.Builder()
                .get()
                .url(url)
                .build();
        httpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                if (mOkhttpInterface!=null){
                    //切換到主執行緒
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            mOkhttpInterface.Failed(e);
                        }
                    });
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response!=null&&response.isSuccessful()){
                    final String data = response.body().string();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (mOkhttpInterface!=null){
                                mOkhttpInterface.Success(data);
                                return;
                            }
                        }
                    });
                }
            }
        });
    }
    //單例模式
    public static HttpUtils getInstance(){
        if (mHttpUtils==null){
            synchronized (HttpUtils.class){
                if (mHttpUtils==null){
                    return mHttpUtils=new HttpUtils();
                }
            }
        }
        return mHttpUtils;
    }
}

ShopPresenter P層

package wanghuiqi.bawie.com.whq_shop.presenter;
import com.google.gson.Gson;
import java.util.List;
import wanghuiqi.bawie.com.whq_shop.model.HttpUtils;
import wanghuiqi.bawie.com.whq_shop.model.bean.Shop;

public class ShopPresenter {
    public void ShopData(String url) {
        HttpUtils.getInstance().doGet(url, new HttpUtils.OKhttpInterface() {
            @Override
            public void Failed(Exception e) {
                mOnshopInterface.failed(e);
            }

            @Override
            public void Success(String data) {
                Shop shop = new Gson().fromJson(data, Shop.class);
                List<Shop.DataBean> shopData = shop.getData();
                mOnshopInterface.success(shopData);
            }
        });
    }

    public interface onShopInterface {
        void failed(Exception e);

        void success(List<Shop.DataBean> shopData);
    }

    private onShopInterface mOnshopInterface;

    public void setOnshopInterface(onShopInterface onshopInterface) {
        mOnshopInterface = onshopInterface;
    }
}

MainActivity

package wanghuiqi.bawie.com.whq_shop;

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 java.util.List;

import wanghuiqi.bawie.com.whq_shop.adapter.ShopAdapter;
import wanghuiqi.bawie.com.whq_shop.model.bean.Shop;
import wanghuiqi.bawie.com.whq_shop.presenter.ShopPresenter;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ExpandableListView ex_listView;
    private CheckBox all_box;
    private TextView all_price;
    private Button jiesuan_btn;
    private ShopAdapter shopAdapter;
    private String url = "http://www.zhaoapi.cn/product/getCarts?uid=71";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //A.獲取控制元件
        initView();
        //B.獲取資料
        initData();
    }

    //B.獲取資料
    private void initData() {
        ShopPresenter shopPresenter = new ShopPresenter();
        shopPresenter.ShopData(url);
        shopPresenter.setOnshopInterface(new ShopPresenter.onShopInterface() {

            @Override
            public void failed(Exception e) {

            }

            @Override
            public void success(List<Shop.DataBean> shopData) {
                //B1.獲取介面卡
                shopAdapter = new ShopAdapter(shopData);
                //B2.對介面卡設定監聽(加減器,組,子條目複選框改變)
                shopAdapter.setOnCartListChangeListener(new ShopAdapter.onCartListChangeListener() {
                    //------B2.1.組的複選框被點選------
                    @Override
                    public void onParentCheckedChange(int groupPosition) {
                        boolean parentAllSelect = shopAdapter.isParentAllSelect(groupPosition);
                        shopAdapter.changeSellerAllProduct(groupPosition, !parentAllSelect);
                        shopAdapter.notifyDataSetChanged();
                        //重新整理底部
                        refreshAllShop();

                    }

                    //-------B2.2.子條目的複選框被點選-------
                    @Override
                    public void onChildCheckedChange(int groupPosition, int childPosition) {
                        shopAdapter.changeChild(groupPosition, childPosition);
                        shopAdapter.notifyDataSetChanged();
                        refreshAllShop();
                    }

                    //-------B2.3.加減器被點選------
                    @Override
                    public void onAddSubNumberChange(int groupPosition, int childPosition, int number) {
                        shopAdapter.changProductNumber(groupPosition, childPosition, number);
                        shopAdapter.notifyDataSetChanged();
                        refreshAllShop();
                    }
                });
                //B3.設定adapter物件
                ex_listView.setAdapter(shopAdapter);
                //B4.展開二級列表
                for (int i=0;i<shopData.size();i++){
                    ex_listView.expandGroup(i);
                }
            }
        });
    }


    //-------底部全選框的點選事件--------
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.all_box:
                boolean allSelected = shopAdapter.isAllSelected();
                shopAdapter.changAllCheckBox(!allSelected);
                shopAdapter.notifyDataSetChanged();
                //重新整理底部的資料顯示
                refreshAllShop();
                break;
        }
    }

    //--------重新整理底部---------
    private void refreshAllShop() {
        //判斷是否所有商品都被選中
        boolean allSelected = shopAdapter.isAllSelected();
        //設定給checkbox
        all_box.setChecked(allSelected);
        //計算總計
        float price = shopAdapter.TotalPrice();
        all_price.setText("總計" + price);
        //計算數量
        int number = shopAdapter.TotalNumber();
        jiesuan_btn.setText("去結算(" + number + ")");

    }


    //A.初始化控制元件
    private void initView() {
        ex_listView = findViewById(R.id.ex_listView);
        all_box = findViewById(R.id.all_box);
        all_price = findViewById(R.id.all_price);
        jiesuan_btn = findViewById(R.id.jiesuan_btn);

        all_box.setOnClickListener(this);
    }
}