这篇文章我们将详细的介绍如何实现ListView的多选操作,文中将会纠正在使用ListViewCHOICE_MODE_MULTIPLE或者CHOICE_MODE_MULTIPLE_MODAL时容易犯的错误,以及
CHOICE_MODE_MULTIPLE与CHOICE_MODE_MULTIPLE_MODAL的区别。最后我们将给出一个demo来演示两种多选操作的实现。
一、在不使用ListView多选模式的情况下
注:我认为这一节可以不看,因为我觉得不使用ListView的多选模式有点愚蠢。
如果我们不知道ListView自带多选模式,那么我们一般是通过维护一个保存被选择position集合来实现多选的,通常情况下这个集合类型我们选择HashSet。
实现的大致框架如下:
Adapter中:
保存被选择的position
1
|
public HashSet<Long> selectedItems =
new
HashSet<Long>();
|
getView中判断当前Position是否在集合中,从而显示不同的外观
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public View getView(int position, View convertView, ViewGroup par) {
......
if
(selectedItems.contains((long)position)){
holder.cBox.setChecked(
true
);
}
else
{
holder.cBox.setChecked(
false
);
}
if
(selectedMode==AppContext.MULTI_SELECTED){
holder.cBox.setVisibility(View.VISIBLE);
holder.check_box_wraper.setVisibility(View.VISIBLE);
}
else
{
holder.cBox.setVisibility(View.GONE);
holder.check_box_wraper.setVisibility(View.GONE);
}
.....
}
|
Activity中:
主要是处理onItemClick事件,在不同模式下,做不同的处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@Override
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
//普通模式 :直接打开一个activity
if
(itemClickActionMode==AppContext.VIEW_NOTE){
Long mId=Long.parseLong(idText.getText().toString());
Uri uri = ContentUris.withAppendedId(getIntent().getData(), mId);
startActivity(
new
Intent(Intent.ACTION_VIEW, uri));
}
//多选模式:更新adapter中selectedItems 集合的值,同时 让adapter在getView中改变item的外观。
else
{
ViewHolder vHollder = (ViewHolder) v.getTag();
if
(mAdapter.selectedItems.contains((long)position)){
mAdapter.selectedItems.remove((long)position);
}
else
{
mAdapter.selectedItems.add((long)position);
}
mAdapter.notifyDataSetChanged();
onItemSelected(getSelectedCount());
}
}
|
上面的做法其实用的很普遍。但是我们不提倡。
二、使用ListViiew的CHOICE_MODE_MULTIPLE模式
ListView有四种模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* Normal list that does not indicate choices
*/
public static final int CHOICE_MODE_NONE = 0;
/**
* The list allows up to one choice
*/
public static final int CHOICE_MODE_SINGLE = 1;
/**
* The list allows multiple choices
*/
public static final int CHOICE_MODE_MULTIPLE = 2;
/**
* The list allows multiple choices in a modal selection mode
*/
public static final int CHOICE_MODE_MULTIPLE_MODAL = 3;
|
其中CHOICE_MODE_NONE
是普通模式,CHOICE_MODE_SINGLE
是单选模式,不常用,CHOICE_MODE_MULTIPLE
和CHOICE_MODE_MULTIPLE_MODAL
都是多选模式,他们的区别稍后我们会讲到。
所以ListView在设计的时候其实是考虑了多选操作的,我们没有必要自己再像第一节描述的那样专门维护一个HashSet来保存被选择的position。实现ListView的多选操作的代码在ListView直接父类AbsListView中,AbsListView已经有一个mCheckStates变量来做了保存被选择的position这个事情。mCheckStates的定义如下:
1
|
SparseBooleanArray mCheckStates;
|
AbsListView还定义了如下公共方法:
//判断一个item是否被选中
1
|
public boolean isItemChecked(int position);
|
//获得被选中item的总数
1
|
public int getCheckedItemCount();
|
//选中一个item
1
|
public void setItemChecked(int position, boolean value);
|
//清除选中的item
1
|
public void clearChoices();
|
当点击一个item的时候absListView中会调用performItemClick,如果是CHOICE_MODE_MULTIPLE,则该item点击一次,mCheckStates中相应位置的状态变更一次。然后我们就可以通过listView的getCheckedItemCount()方法获取选择了多少个;isItemChecked(int position)方法判断一个item是不是被选中。
有了这些原生sdk的支持,难道还有什么多选操作是不能实现的吗?所以是不是应该考虑放弃第一节中描述的那种方法了呢?遗憾的是很多android开发者即使是用了CHOICE_MODE_MULTIPLE,仍然没有去利用这些ListView自带的功能,估计是根本不知道该CHOICE_MODE_MULTIPLE的 特性吧,这其实也是android程序员与ios程序员真正存在差距的地方。
CHOICE_MODE_MULTIPLE实战
先看看效果图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|