此篇文章写于较早时期,已于2019年进行完善
前期篇名:Android进阶之路 - RecyclerView记录CheckBox选取数据
当前篇名:Android进阶之路 - 实现常见购物车功能
2017版:目前没有把全选、取消全选、反选的功能集成到此Demo中,只实现了基本的选取记录与记录功能
2019版:优化无效代码,同时完善反选、全选、取消全选功能

此篇 - 开发中心思想

使用Map<Intenger,Boolean>集合来存储对应角标、对应状态,在使用中如某一条信息被选取,那么就记录当前的角标位为true,即设为被选取的状态;

当需要获得选取数据之时,循环总数据源内map为true的角标,然后将对应数据存储到新的List中即可!

  • 2017年的残缺版
  • 代码:MainActivity
  • 布局:activity_main
  • 布局:item_layout
  • 2019年的精简版
  • 代码:MainActivity
  • 布局:activity_main
  • 代码:CheckAdapter
  • 布局:item_layout


存在问题、解决方案

问题:RecyclerView\checkBox的复用问题,导致checkBox出现选取0角标的box时候角标10同样被选取
解决:给予CheckBox的状态记录

2017年的残缺版

build

compile 'com.android.support:recyclerview-v7:24.2.1'

Effect

android 购物车动画 android 购物车实现_Boo

代码:MainActivity
package com.yl.checkbox.checkboxdata;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private RecyclerView mRvView;
    private TextView mAll;
    private TextView mCancel;
    private TextView mInvert;
    private CheckAdapter checkAdapter;
    private List<String> lists;
    private List<String>listDatas=new ArrayList<>();
    private TextView mGetData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lists = new ArrayList<>();
        for(int i=0;i<20;i++){
            lists.add("没有什么能够阻挡,天马星空的梦想"+i);
        }

        initView();
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        mRvView.setLayoutManager(linearLayoutManager);
        checkAdapter = new CheckAdapter(this, lists);
        mRvView.setAdapter(checkAdapter);

        //子条目监听
        checkAdapter.setItemClickListener(new RecyclerViewOnItemClickListener() {
            @Override
            public void onItemClickListener(View view, int position) {
                Toast.makeText(MainActivity.this,"If you are happy - "+ position,Toast.LENGTH_SHORT).show();
                //设置选中的项
                checkAdapter.setSelectItem(position);
            }
        });
    }

    private void initView() {
        mRvView = (RecyclerView) findViewById(R.id.rv_view);
        mAll = (TextView) findViewById(R.id.tv_all);
        mCancel = (TextView) findViewById(R.id.tv_cancel);
        mInvert = (TextView) findViewById(R.id.tv_invert);
        mGetData = (TextView) findViewById(R.id.tv_getData);
        mAll.setOnClickListener(this);
        mCancel.setOnClickListener(this);
        mInvert.setOnClickListener(this);
        mGetData.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.tv_getData:
                String content ="";
                listDatas.clear();

                Toast.makeText(MainActivity.this,"获取我们选取的数据",Toast.LENGTH_SHORT).show();
                Log.e("TAG",mGetData.getText().toString());

                Map<Integer, Boolean> map = checkAdapter.getMap();
                for(int i =0;i<lists.size();i++){
                    if(map.get(i)){
                        listDatas.add(lists.get(i));
                    }
                }
                //这里是为了测试我们的结果 ,可忽略!
                for (int j=0;j<listDatas.size();j++){
                    Log.e("TAG",listDatas.get(j));
                    content+=listDatas.get(j);
                }
                mGetData.setText(content);
                Log.e("TAG",content);
                break;
                
            //以下三个功能后续扩展
            case R.id.tv_all:
                Toast.makeText(MainActivity.this,"全选",Toast.LENGTH_SHORT).show();
                break;
            case R.id.tv_cancel:
                Toast.makeText(MainActivity.this,"取消全选",Toast.LENGTH_SHORT).show();
                break;
            case R.id.tv_invert:
                Toast.makeText(MainActivity.this,"反选",Toast.LENGTH_SHORT).show();
                break;
        }
    }

    //Adapter数据填充
    class CheckAdapter extends RecyclerView.Adapter<CheckAdapter.CheckViewHolder>{
        private Context mContext;
        private List<String> lists;
        private HashMap<Integer,Boolean>Maps=new HashMap<Integer,Boolean>();
        private HashMap<Integer,Boolean>AllMaps=new HashMap<Integer,Boolean>();
        public RecyclerViewOnItemClickListener onItemClickListener;

        //成员方法,初始化checkBox的状态,默认全部不选中
        public CheckAdapter(Context context, List<String> lists){
            this.mContext=context;
            this.lists=lists;
            initMap();
        }

        //初始化map内的数据状态,全部重置为false,即为选取状态
        private void initMap() {
            for (int i = 0; i < lists.size(); i++) {
                Maps.put(i, false);
            }
        }

        //获取最终的map存储数据
        public Map<Integer,Boolean>getMap(){
            return Maps;
        }

        //后续扩展 - 获取最终的map存储数据
        public Map<Integer,Boolean>getAllMap(){
            return AllMaps;
        }

        //点击item选中CheckBox
        public void setSelectItem(int position) {
            //对当前状态取反
            if (Maps.get(position)) {
                Maps.put(position, false);
            } else {
                Maps.put(position, true);
            }
            notifyItemChanged(position);
        }
        @Override
        public CheckAdapter.CheckViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            CheckViewHolder checkViewHolder = new CheckViewHolder(LayoutInflater.from(MainActivity.this).inflate(R.layout.item_layout, parent,false),onItemClickListener);
            return checkViewHolder;
        }

        @Override
        public void onBindViewHolder(CheckAdapter.CheckViewHolder holder, final int position) {

            holder.mName.setText(lists.get(position));
            holder.mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    Maps.put(position,isChecked);
                }
            });

            if(Maps.get(position)==null){
                Maps.put(position,false);
            }
            //没有设置tag之前会有item重复选框出现,设置tag之后,此问题解决
            holder.mCheckBox.setChecked(Maps.get(position));

            //之后扩展使用
            AllMaps.put(position,true);
        }

        @Override
        public int getItemCount() {
            return lists ==null?0:lists.size();
        }

        public void setItemClickListener(RecyclerViewOnItemClickListener onItemClickListener) {
            this.onItemClickListener = onItemClickListener;
        }

        class CheckViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
            private RecyclerViewOnItemClickListener mListener;
            private  TextView mName;
            private  CheckBox mCheckBox;
            public CheckViewHolder(View itemView,RecyclerViewOnItemClickListener onItemClickListener) {
                super(itemView);
                this.mListener = onItemClickListener;
                itemView.setOnClickListener(this);
                mName = (TextView) itemView.findViewById(R.id.item_name);
                mCheckBox = (CheckBox) itemView.findViewById(R.id.item_cb);
            }

            @Override
            public void onClick(View v) {
                if (mListener != null) {
                    mListener.onItemClickListener(v, getPosition());
                }
            }
        }
    }

    //接口回调设置点击事件
    public interface RecyclerViewOnItemClickListener {
        //点击事件
        void onItemClickListener(View view, int position);
    }
}
布局:activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context="com.yl.checkbox.checkboxdata.MainActivity">

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

        <TextView
            android:id="@+id/tv_all"
            android:layout_width="0dp"
            android:layout_height="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="全选" />

        <TextView
            android:id="@+id/tv_cancel"
            android:layout_width="0dp"
            android:layout_height="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="取消全选" />

        <TextView
            android:id="@+id/tv_invert"
            android:layout_width="0dp"
            android:layout_height="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="反选" />
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#21aae3" />

    <TextView
        android:id="@+id/tv_getData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="5dp"
        android:text="获取选取数据" />

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#21aae3" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</LinearLayout>
布局:item_layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/item_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="5dp"
        tools:text="默认数据" />

    <android.support.v7.widget.AppCompatCheckBox
        android:id="@+id/item_cb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

build

compile 'com.android.support:recyclerview-v7:24.2.1'

Effect

android 购物车动画 android 购物车实现_android_02

代码:MainActivity
package nkwl.com.shopcardemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

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

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private RecyclerView mRvView;
    private TextView mAll;
    private TextView mCancel;
    private TextView mInvert;
    private CheckAdapter checkAdapter;
    private List<String> lists;
    private List<String> listDates = new ArrayList<>();
    private TextView mGetData;
    private TextView mContent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initAdapter();
    }

    private void initView() {
        //模拟数据
        lists = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            lists.add("商品 - " + i);
        }

        mRvView = (RecyclerView) findViewById(R.id.rv_view);
        mAll = (TextView) findViewById(R.id.tv_all);
        mCancel = (TextView) findViewById(R.id.tv_cancel);
        mInvert = (TextView) findViewById(R.id.tv_invert);
        mGetData = (TextView) findViewById(R.id.tv_getData);
        mContent = (TextView) findViewById(R.id.tv_content);
        mAll.setOnClickListener(this);
        mCancel.setOnClickListener(this);
        mInvert.setOnClickListener(this);
        mGetData.setOnClickListener(this);
    }

    private void initAdapter() {
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        mRvView.setLayoutManager(linearLayoutManager);
        checkAdapter = new CheckAdapter(this, lists);
        mRvView.setAdapter(checkAdapter);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tv_getData:
                String content = "";
                listDates.clear();

                Map<Integer, Boolean> map = checkAdapter.getMap();
                for (int i = 0; i < lists.size(); i++) {
                    if (map.get(i)) {
                        listDates.add(lists.get(i));
                    }
                }

                //这里是为了测试我们的结果 ,可忽略!
                for (int j = 0; j < listDates.size(); j++) {
                    content += listDates.get(j);
                }
                mContent.setText(content);
                break;

            case R.id.tv_all:
                Toast.makeText(MainActivity.this, "全选", Toast.LENGTH_SHORT).show();
                checkAdapter.allMap();
                break;

            case R.id.tv_cancel:
                Toast.makeText(MainActivity.this, "取消全选", Toast.LENGTH_SHORT).show();
                checkAdapter.cancelAllMap();
                break;

            case R.id.tv_invert:
                Toast.makeText(MainActivity.this, "反选", Toast.LENGTH_SHORT).show();
                checkAdapter.invertMap();
                break;
            default:
                break;

        }
    }
}
布局:activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:minHeight="100dp"
        android:padding="5dp"
        android:text="Display Content" />

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#21aae3" />

    <TextView
        android:id="@+id/tv_getData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="5dp"
        android:text="获取选取数据" />

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#21aae3" />

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

        <TextView
            android:id="@+id/tv_all"
            android:layout_width="0dp"
            android:layout_height="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="全选" />

        <TextView
            android:id="@+id/tv_cancel"
            android:layout_width="0dp"
            android:layout_height="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="取消全选" />

        <TextView
            android:id="@+id/tv_invert"
            android:layout_width="0dp"
            android:layout_height="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="反选" />
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#21aae3" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>
</LinearLayout>
代码:CheckAdapter
package nkwl.com.shopcardemo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author MrLiu
 * @date 2019/12/12
 * desc
 */
public class CheckAdapter extends RecyclerView.Adapter<CheckAdapter.CheckViewHolder> {
    private Context mContext;
    private List<String> lists;
    private HashMap<Integer, Boolean> Maps = new HashMap<Integer, Boolean>();

    //成员方法,初始化checkBox的状态,默认全部不选中
    public CheckAdapter(Context context, List<String> lists) {
        this.mContext = context;
        this.lists = lists;
        initMap();
    }

    //初始化map内的数据状态,全部重置为false,即为选取状态
    private void initMap() {
        for (int i = 0; i < lists.size(); i++) {
            Maps.put(i, false);
        }
    }

    //获取最终的map存储数据
    public Map<Integer, Boolean> getMap() {
        return Maps;
    }

    //全选
    public Map<Integer, Boolean> allMap() {
        for (int i = 0; i < lists.size(); i++) {
            Maps.put(i, true);
        }
        notifyDataSetChanged();
        return Maps;
    }

    //取消全选
    public Map<Integer, Boolean> cancelAllMap() {
        for (int i = 0; i < lists.size(); i++) {
            Maps.put(i, false);
        }
        notifyDataSetChanged();
        return Maps;
    }

    //反选
    public Map<Integer, Boolean> invertMap() {
        for (Integer key : Maps.keySet()) {
            Boolean state = Maps.get(key);
            if (state) {
                Maps.put(key, false);
            } else {
                Maps.put(key, true);
            }
        }
        notifyDataSetChanged();
        return Maps;
    }

    @Override
    public CheckAdapter.CheckViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        CheckAdapter.CheckViewHolder checkViewHolder = new CheckAdapter.CheckViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_layout, parent, false));
        return checkViewHolder;
    }

    @Override
    public void onBindViewHolder(CheckAdapter.CheckViewHolder holder, final int position) {
        holder.mName.setText(lists.get(position));
        holder.mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Maps.put(position, isChecked);
            }
        });

        if (Maps.get(position) == null) {
            Maps.put(position, false);
        }
        //没有设置tag之前会有item重复选框出现,设置tag之后,此问题解决
        holder.mCheckBox.setChecked(Maps.get(position));
    }

    @Override
    public int getItemCount() {
        return lists == null ? 0 : lists.size();
    }

    class CheckViewHolder extends RecyclerView.ViewHolder {
        private TextView mName;
        private CheckBox mCheckBox;

        public CheckViewHolder(View itemView) {
            super(itemView);
            mName = (TextView) itemView.findViewById(R.id.item_name);
            mCheckBox = (CheckBox) itemView.findViewById(R.id.item_cb);
        }
    }
}
布局:item_layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/item_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="5dp"
        tools:text="默认数据" />

    <android.support.v7.widget.AppCompatCheckBox
        android:id="@+id/item_cb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>