ListView+CheckBox实现全选,全不选功能
项目中有一个需求,选择联系人进行发送消息,可以实现全选,或者全不选,或者取消某一个已选中的.当点击确定按钮时,获取到已勾选的联系人信息.这里先来一张效果图:
点击确定按钮后,输出已勾选联系人信息.
这里先把几个关键地方提一下:
-
listView+checkBox时,listView的item焦点会失去点击效果
- 原因:开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了,可能会发生点击每一个item的时候没有反应,无法获取的焦点。原因多半是由于在你自己定义的Item中存在诸如ImageButton,Button,CheckBox等子控件(也可以说是Button或者Checkable的子类控件),由于这些控件是强焦点控件,此时这些控件会抢占Item的焦点,所以常常当点击item时变化的是子控件,item本身的点击没有响应。解决方法有很多种,如使用焦点比较弱的控件,或者自己去处理事件分发来解决焦点冲突。下面给大家介绍一种比较简单的方法。
-
解决方法:在listView 的item 布局的顶层布局中 添加属android:descendantFocusability=”blocksDescendants”,就可以很简单的解决了。
- 我们看一下android:descendantFocusability属性:API描述如下:android:descendantFocusability
Defines the relationship between the ViewGroup and its descendants when looking for a View to take focus.
Must be one of the following constant values.该属性是当一个为view获取焦点时,定义viewGroup和其子控件两者之间的关系。
属性的值有三种:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
-
当点击Item时,CheckBox实现联动效果(上一步已经处理了Item的焦点)
- 只需要添加ListView的点击事件,在点击事件中实现CheckBox联动效果。伪代码:
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TestCheckAllAdapter.ViewHolder holder = (TestCheckAllAdapter.ViewHolder) view.getTag();
// 会自动触发CheckBox的checked事件
holder.checkBox.toggle();
}
-
修改CheckBox的样式
-
首先,我们定义一个状态选择器(两张图片,一张是normal状态,另一种是pressed状态):
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checkable="true" android:drawable="@drawable/checkbox_pressed" />
<item android:state_checked="true" android:drawable="@drawable/checkbox_pressed" />
<item android:state_pressed="true" android:drawable="@drawable/checkbox_pressed" />
<item android:drawable="@drawable/checkbox_normal" />
</selector>
-
然后在style布局中添加CheckBox样式:
<!--自定义CheckBox的样式-->
<style name="CustomCheckboxTheme" parent="@android:style/Widget.CompoundButton.CheckBox">
<item name="android:button">@drawable/selector_checkbox</item>
</style>
-
最后,在布局中引入自定义CheckBox样式:
<CheckBox
android:id="@+id/cb_check"
style="@style/CustomCheckboxTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:focusable="false" />
-
全选,全不选实现
这里就不细说了,代码中注释很详细.
Activity类:
/**
* Created by ListenerGao on 2016/8/29.
* <p/>
* listView实现全选,全不选功能
*/
public class TestCheckAll extends BaseActivity implements AdapterView.OnItemClickListener {
private static final String TAG = "TestCheckAll";
@BindView(R.id.tv_check)
TextView tvCheck;
@BindView(R.id.lv_check)
ListView lvCheck;
@BindView(R.id.ib_arrow_left)
ImageButton ibArrowLeft;
@BindView(R.id.bt_confirm)
Button btConfirm;
private List<TestCheckBean> mData;
private TestCheckAllAdapter mAdapter;
@Override
protected int getLayoutResId() {
return R.layout.activity_test_checkall;
}
@Override
protected void initView() {
ButterKnife.bind(this);
tvCheck.setVisibility(View.VISIBLE);
tvCheck.setText("全选");
ibArrowLeft.setVisibility(View.VISIBLE);
}
@Override
protected void initData() {
//初始化数据
mData = new ArrayList<>();
for (int i = 0; i < 15; i++) {
TestCheckBean testCheckBean = new TestCheckBean(i, "张三" + i);
mData.add(testCheckBean);
}
mAdapter = new TestCheckAllAdapter(this, mData);
lvCheck.setAdapter(mAdapter);
lvCheck.setOnItemClickListener(this);
}
@OnClick({R.id.ib_arrow_left, R.id.tv_check, R.id.bt_confirm})
public void onClick(View view) {
switch (view.getId()) {
case R.id.ib_arrow_left:
finish();
break;
case R.id.tv_check:
if (tvCheck.getText().equals("全选")) {
mAdapter.initCheckBox(true);
mAdapter.notifyDataSetChanged();
tvCheck.setText("全不选");
} else if (tvCheck.getText().equals("全不选")) {
mAdapter.initCheckBox(false);
mAdapter.notifyDataSetChanged();
tvCheck.setText("全选");
}
break;
case R.id.bt_confirm:
//得到选中状态条目的数据Bean
Map<Integer, Boolean> checkedMap = mAdapter.getCheckedMap();
List<TestCheckBean> allChecked = new ArrayList<>();
for (int i = 0; i < checkedMap.size(); i++) {
if (checkedMap.get(i)) {
TestCheckBean testCheckBean = mData.get(i);
allChecked.add(testCheckBean);
}
}
//遍历输出已勾选条目的数据Bean
for (TestCheckBean bean : allChecked) {
Log.d(TAG, bean.toString());
}
break;
}
}
/**
* listView+checkBox时,listView的item焦点会失去点击。
* 需要在listView 的item 布局的顶层布局中 添加属性:android:descendantFocusability="blocksDescendants"
* 当点击item时checkBox实现联动效果
*/
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TestCheckAllAdapter.ViewHolder holder = (TestCheckAllAdapter.ViewHolder) view.getTag();
// 会自动触发CheckBox的checked事件
holder.checkBox.toggle();
}
}
Adapter类:
/**
* Created by ListenerGao on 2016/8/29.
*/
public class TestCheckAllAdapter extends BaseAdapter {
private Context mContext;
private List<TestCheckBean> mData;
//存储CheckBox状态的集合
private Map<Integer,Boolean> checkedMap;
public TestCheckAllAdapter(Context context, List<TestCheckBean> data) {
this.mContext = context;
this.mData = data;
checkedMap = new HashMap<>();
//默认CheckBox为未勾选状态
initCheckBox(false);
}
/**
* 初始化Map集合
* @param isChecked CheckBox状态
*/
public void initCheckBox(boolean isChecked) {
for (int i = 0; i<mData.size();i++) {
checkedMap.put(i,isChecked);
}
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_test_checkall,null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvName.setText(mData.get(position).getName());
// 勾选框的点击事件
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// 当勾选框状态发生改变时,重新存入map集合
checkedMap.put(position,isChecked);
}
});
//设置勾选框的状态
holder.checkBox.setChecked(checkedMap.get(position));
return convertView;
}
/**
* 得到勾选状态的集合
* @return
*/
public Map<Integer,Boolean> getCheckedMap() {
return checkedMap;
}
public static class ViewHolder{
@BindView(R.id.tv_name)
public TextView tvName;
@BindView(R.id.cb_check)
public CheckBox checkBox;
public ViewHolder(View view) {
ButterKnife.bind(this,view);
}
}
}