android 实现ListView嵌套Checkbox实现真正的多选、全选、反选、取消
我们在开发APP的时候,很多情况下会使用到ListView嵌套CheckBox的情况,例如购物车选择商品的情况,其实很多人要说这个其实很简单了,并没有那么复杂,事实上并非如此,我们在使用ListView嵌套CheckBox复选框的时候会出现很多问题,接下来我将用一篇博客来说明这些问题,给大家一些参照,解决ListView嵌套Checkbox解决复用问题。
效果图如下:
首先,我们先看MainActivity中的布局,
<?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="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:divider="#808080"
android:dividerHeight="0.1dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<Button
android:id="@+id/btn_all_select"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="全选" />
<Button
android:id="@+id/btn_all_unselect"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="反选" />
<Button
android:id="@+id/btn_delete"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="delete"
android:text="删除" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="取消" />
</LinearLayout>
</LinearLayout>
接下来看MainActivity的代码如下:
package com.example.cx.listviewdemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ListView mLv;
private Button mBtnSelectAll, mBtnUnSelectAll, mBtnDelete, mBtnCancel;
//数据源
private List<String> mDataList;
//与条目对应的选中状态
private List<Boolean> mCheckedList;
private MyAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
mDataList = new ArrayList<String>();
mCheckedList = new ArrayList<Boolean>();
for (int i = 0; i < 50; i++) {
mDataList.add("数据" + i);
mCheckedList.add(false);
}
mAdapter = new MyAdapter(MainActivity.this, mDataList);
mAdapter.setData(mDataList, mCheckedList);
mLv.setAdapter(mAdapter);
mLv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, "条目" + position + "被点击了", Toast.LENGTH_SHORT).show();
mCheckedList.set(position, !mCheckedList.get(position));
mAdapter.setData(mDataList, mCheckedList);
mAdapter.notifyDataSetChanged();
}
});
}
private void initView() {
mLv = (ListView) findViewById(R.id.lv);
mBtnSelectAll = findViewById(R.id.btn_all_select);
mBtnUnSelectAll = findViewById(R.id.btn_all_unselect);
mBtnDelete = findViewById(R.id.btn_delete);
mBtnCancel = findViewById(R.id.btn_cancel);
mBtnSelectAll.setOnClickListener(this);
mBtnUnSelectAll.setOnClickListener(this);
mBtnDelete.setOnClickListener(this);
mBtnCancel.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
//全选
case R.id.btn_all_select:
select_all();
break;
//反选
case R.id.btn_all_unselect:
unselect_all();
break;
//删除
case R.id.btn_delete:
delete();
break;
//取消
case R.id.btn_cancel:
cancel();
break;
}
}
// 全选
private void select_all() {
for (int i = 0; i < mCheckedList.size(); i++) {
mCheckedList.set(i, true);
}
mAdapter.setData(mDataList, mCheckedList);
mAdapter.notifyDataSetChanged();
}
//取消
private void cancel() {
for (int i = 0; i < mCheckedList.size(); i++) {
mCheckedList.set(i, false);
}
mAdapter.setData(mDataList, mCheckedList);
mAdapter.notifyDataSetChanged();
}
//删除
private void delete() {
for (int i = 0; i < mCheckedList.size(); i++) {
if (mCheckedList.get(i)) {
mCheckedList.remove(i);
mDataList.remove(i);
i--;
}
}
mAdapter.setData(mDataList, mCheckedList);
mAdapter.notifyDataSetChanged();
}
//反选
private void unselect_all() {
for (int i = 0; i < mCheckedList.size(); i++) {
mCheckedList.set(i, !mCheckedList.get(i));
}
mAdapter.setData(mDataList, mCheckedList);
mAdapter.notifyDataSetChanged();
}
}
主要是Adapter 的代码,里面解决了ListView 嵌套CheckBox的问题。比如,当选中item中的checkbox时然后上下滑动,这时你会发现item会被复用,什么意思呢?就是当你上下滑动listView时,选中的checkbox会被取消,这个问题跟listview加载图片时会错位一样,都是事件分发机制造成的,具体解决接下来看操作:
package com.example.cx.listviewdemo;
import android.content.Context;
import android.content.SharedPreferences;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import java.util.List;
public class MyAdapter extends BaseAdapter {
private Context mContext;
private List<String> mDataList;
private List<Boolean> mCheckedList;
private SharedPreferences mSp;
public MyAdapter(Context context, List<String> mDataList) {
this.mContext = context;
this.mDataList = mDataList;
mSp = mContext.getSharedPreferences("config", Context.MODE_PRIVATE);
}
//会被多次调用(只要ListView条目个数发生变化的时候)
public void setData(List<String> dataList, List<Boolean> checkedList) {
this.mDataList = dataList;
this.mCheckedList = checkedList;
}
@Override
public int getCount() {
return mDataList.size();
}
@Override
public Object getItem(int position) {
return mDataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
//图片错位: 给加载的图片设计tag(url)标记,复用之后再次滑动当前条目,判断当前图片URL和这个Tag标记是否一致,如果一致就显示,如果不一致就不显示
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (viewHolder == null) {
viewHolder = new ViewHolder();
convertView = View.inflate(mContext, R.layout.layout_list_item, null);
viewHolder.mTv = convertView.findViewById(R.id.item_tv);
viewHolder.mCb = convertView.findViewById(R.id.item_cb);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.mTv.setText(mDataList.get(position));
viewHolder.mCb.setChecked(mCheckedList.get(position));
viewHolder.mCb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mCheckedList.set(position, isChecked);
notifyDataSetChanged();
}
});
return convertView;
}
public static class ViewHolder {
TextView mTv;
CheckBox mCb;
}
}
这是适配器布局代码:
<?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="60dp"
android:gravity="center_vertical"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:descendantFocusability="blocksDescendants" //防止listview与checkbox点击造成冲突
android:orientation="horizontal">
<TextView
android:id="@+id/item_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
/>
<CheckBox
android:id="@+id/item_cb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp" />
</RelativeLayout>
这样我们就实现了ListView嵌套Checkbox实现真正的多选、全选、反选、取消。