此篇文章写于较早时期,已于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
代码: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
代码: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>