您的位置:首页 > 移动开发 > Android开发

Android 中使用ListView和CheckBox进行批量操作

2013-06-02 23:00 447 查看
在使用ListView时,一般为了性能的提升,都会使用ViewHolder,也就是Item的View实现复用。

现在的问题是,当在ListView的Item中包含CheckBox,并且CheckBox的事件处理监听器是holder.checkbox.setOnCheckedChangeListener()时,会出现第一项开始未选中,当第二项选中时第一项也跟着选中,这显然不是我们想要的结果。

出现这个问题的原因是第一项和第二项用的是同一个Item,当第二项选中时,CheckBox的当前状态为选中,这时setOnCheckedChangeListener里面会改变第一项关联的实体对象的属性(引用类型,变量A、B都引用同一个对象AA,当A把AA的某个属性值修改了,B再次访问时,AA对象的那个属性的值为A引用改后的值),代码如下:

查看源码

打印?

1
holder.checkbox.setOnCheckedChangeListener(
new

OnCheckedChangeListener(){
2
3
@Override
4
public

void
onCheckedChanged(CompoundButtonbuttonView,
boolean
isChecked){
5
driver.setSelected(isChecked);
6
}
7
8
});
解决办法:

1、在ListViewAdapter初始化时,将对象中有关CheckBox是否选中的属性存储起来。

查看源码

打印?

1
selectedMap=
new

HashMap<Integer,Boolean>();
2
int

size=mPersons.size();
3
for

(
int

i=
0
;i<size;i++){
4
selectedMap.put(i,mPersons.get(i).isSelected());
5
}
2、去掉CheckBox的holder.checkbox.setOnCheckedChangeListener(){}事件监听器

3、在Adapter里的publicViewgetView(finalintposition,ViewconvertView,ViewGroupparent){}方法体里面,当前的CheckBox是否选中状态,由之前初始化时保存的对象属性值控制,代码如下:

查看源码

打印?

1
boolean

selected=selectedMap.get(position);
2
holder.checkbox.setChecked(selected);
3、用户点击ListView的Item时,改变CheckBox的状态,代码如下:

查看源码

打印?

1
convertView.setOnClickListener(
new

View.OnClickListener(){
2
3
@Override
4
public

void
onClick(Viewv){
5
checkbox.toggle();
6
selectedMap.put(position,checkbox.isChecked());
7
driver.setSelected(checkbox.isChecked());
8
}
9
});
数据适配器ListViewAdapter的完整代码:

查看源码

打印?

001
package

com.easipass.cloud.ccp.adapter;
002
003
import

java.util.ArrayList;
004
import

java.util.HashMap;
005
006
import

android.content.Context;
007
import

android.view.LayoutInflater;
008
import

android.view.View;
009
import

android.view.ViewGroup;
010
import

android.widget.BaseAdapter;
011
import

android.widget.CheckBox;
012
import

android.widget.Filter;
013
import

android.widget.Filterable;
014
import

android.widget.ImageView;
015
import

android.widget.TextView;
016
017
import

com.easipass.R;
018
import

com.easipass.cloud.ccp.entity.UserInfo;
019
020
/**
021
*用户列表数据适配器
022
*
023
*@authorandroid_ls
024
*/
025
public
final
class
UserListViewAdapter
extends
BaseAdapter
implements
Filterable{
026
private

LayoutInflaterinflater;
027
028
private

MyFiltermyFilter;
029
030
private

final
ObjectmLock=

new
Object();
031
032
private

ArrayList<UserInfo>mPersons;
033
034
private

ArrayList<UserInfo>mCheckValues;
035
036
public

HashMap<Integer,Boolean>selectedMap;
037
038
public

UserListViewAdapter(Contextcontext,ArrayList<UserInfo>cms){
039
inflater=LayoutInflater.from(context);
040
mPersons=cms;
041
042
selectedMap=
new
HashMap<Integer,Boolean>();
043
int

size=mPersons.size();
044
for

(
int

i=
0
;i<size;i++){
045
selectedMap.put(i,mPersons.get(i).isSelected());
046
}
047
048
}

049
050
@Override
051
public

int
getCount(){

052
return

mPersons.size();
053
}

054
055
@Override
056
public

ObjectgetItem(
int

arg0){
057
return

mPersons.get(arg0);
058
}

059
060
@Override
061
public

long
getItemId(
int

position){
062
return

position;
063
}

064
065
@Override
066
public

ViewgetView(
final

int
position,ViewconvertView,ViewGroupparent){
067
ViewHolderholder=
null
;
068
if

(convertView==
null
){
069
convertView=inflater.inflate(R.layout.ccp_carmanager_lv_item,
null
);
070
holder=
new
ViewHolder();
071
holder.text1=(TextView)convertView.findViewById(R.id.tv_name);
072
holder.text2=(TextView)convertView.findViewById(R.id.tv_phnoe);
073
holder.checkbox=(CheckBox)convertView.findViewById(R.id.checkbox);
074
holder.imageView=(ImageView)convertView.findViewById(R.id.iv_icon);
075
076
convertView.setTag(holder);
077
}
else
{
078
holder=(ViewHolder)convertView.getTag();
079
}
080
081
final

UserInfodriver=mPersons.get(position);
082
083
holder.text1.setText(driver.getName());
084
085
holder.text2.setText(driver.getPhoneNumber());
086
//TODO测试
087
holder.imageView.setBackgroundResource(Integer.valueOf(driver.getIconUrl()));
088
holder.checkbox.setVisibility(View.VISIBLE);
089
090
boolean

selected=selectedMap.get(position);
091
holder.checkbox.setChecked(selected);
092
093
final

CheckBoxcheckbox=holder.checkbox;
094
convertView.setOnClickListener(
new

View.OnClickListener(){
095
096
@Override
097
public

void
onClick(Viewv){
098
checkbox.toggle();
099
selectedMap.put(position,checkbox.isChecked());
100
driver.setSelected(checkbox.isChecked());
101
}
102
});
103
104
if

(selected){
105
convertView.setClickable(
false
);
106
}
107
108
return

convertView;
109
}

110
111
@Override
112
public

FiltergetFilter(){
113
if

(myFilter==
null
){
114
myFilter=
new
MyFilter();
115
}
116
return

myFilter;
117
}

118
119
class

MyFilter
extends

Filter{
120
121
@Override
122
protected

FilterResultsperformFiltering(CharSequenceprefix){

123
FilterResultsresults=
new
FilterResults();
124
if

(mCheckValues==
null
){
125
synchronized

(mLock){
126
mCheckValues=
new
ArrayList<UserInfo>(mPersons);
127
}
128
}
129
130
if

(prefix==
null

||prefix.length()==
0
){
131
synchronized

(mLock){
132
ArrayList<UserInfo>list=
new
ArrayList<UserInfo>(mCheckValues);
133
results.values=list;
134
results.count=list.size();
135
}
136
}
else
{
137
StringprefixString=prefix.toString().toLowerCase();
138
final

ArrayList<UserInfo>values=mCheckValues;
139
final

int
count=values.size();
140
141
final

ArrayList<UserInfo>newValues=
new

ArrayList<UserInfo>(count);
142
for

(
int

i=
0
;i<count;i++){
143
final

UserInfovalue=(UserInfo)values.get(i);
144
if

(value.getName().contains(prefixString)){
145
newValues.add(value);
146
}
147
}
148
149
results.values=newValues;
150
results.count=newValues.size();
151
}
152
153
return

results;
154
}
155
156
@SuppressWarnings
(
"unchecked"
)
157
@Override
158
protected

void
publishResults(CharSequenceconstraint,FilterResultsresults){
159
mPersons=(ArrayList<UserInfo>)results.values;
160
if

(results.count>
0
){
161
notifyDataSetChanged();
162
}
else
{
163
notifyDataSetInvalidated();
164
}
165
}
166
}

167
168
static

class
ViewHolder{

169
public

TextViewtext1;
170
171
public

TextViewtext2;
172
173
public

ImageViewimageView;
174
175
public

CheckBoxcheckbox;
176
}

177
178
}
Activity中onCreate()里的写法:

查看源码

打印?

1
mSearchToolbar=(SearchToolbar)

this
.findViewById(R.id.top_search_toolbar);
2
mListView=(ListView)
this
.findViewById(R.id.listview);
3
4
mDriverListAdapter=
new
UserListViewAdapter(
this
,driverList);
5
mListView.setAdapter(mDriverListAdapter);
6
7
mSearchToolbar.setFilter(mDriverListAdapter.getFilter());
SearchToolbar类的代码:

查看源码

打印?

01
package

com.easipass.custom.view;
02
import

android.content.Context;
03
import

android.text.Editable;
04
import

android.text.TextWatcher;
05
import

android.util.AttributeSet;
06
import

android.view.LayoutInflater;
07
import

android.view.View;
08
import

android.widget.AutoCompleteTextView;
09
import

android.widget.FrameLayout;
10
import

android.widget.ImageView;
11
import

android.widget.RelativeLayout;
12
13
import

com.easipass.R;
14
15
/**
16
*功能描述:自定义搜索框组件
17
*@authorandroid_ls
18
*/
19
public
class
SearchToolbar
extends

FrameLayout{
20
21
private

RelativeLayouttopSearchToolbar;
22
23
/**
24
*顶部自动补全文本输入框
25
*/
26
private

AutoCompleteTextViewautoSearch;
27
28
/**
29
*清除搜索结果按钮
30
*/
31
private

ImageViewbtnClearSearch;
32
33
public

SearchToolbar(Contextcontext){
34
super
(context);
35
setupViews();
36
}

37
38
public

SearchToolbar(Contextcontext,AttributeSetattrs){

39
super
(context,attrs);
40
setupViews();
41
}

42
43
private

void
setupViews(){

44
final

LayoutInflatermLayoutInflater=LayoutInflater.from(getContext());
45
topSearchToolbar=(RelativeLayout)mLayoutInflater.inflate(R.layout.top_search_toolbar,
null
);
46
addView(topSearchToolbar);
47
48
btnClearSearch=(ImageView)topSearchToolbar.findViewById(R.id.iv_search_clear);
49
autoSearch=(AutoCompleteTextView)topSearchToolbar.findViewById(R.id.auto_search);
50
}

51
52
public

void
setFilter(
final

android.widget.Filterfilter){
53
autoSearch.addTextChangedListener(
new

TextWatcher(){
54
55
@Override
56
public

void
onTextChanged(CharSequences,
int
start,

int
before,
int

count){
57
StringfilterWord=autoSearch.getText().toString().trim();
58
filter.filter(filterWord);
59
}
60
61
@Override
62
public

void
beforeTextChanged(CharSequences,
int
start,

int
count,
int

after){
63
//TODOAuto-generatedmethodstub
64
65
}
66
67
@Override
68
public

void
afterTextChanged(Editables){
69
//TODOAuto-generatedmethodstub
70
71
}
72
});
73
74
btnClearSearch.setOnClickListener(
new

View.OnClickListener(){
75
76
@Override
77
public

void
onClick(Viewv){
78
autoSearch.setText(
null
);
79
}
80
});
81
}

82
83
}
top_search_toolbar.xml文件:

查看源码

打印?

01
<?
xml

version
=
"1.0"

encoding
=
"utf-8"
?>
02
<
RelativeLayout

xmlns:android
=
"http://schemas.android.com/apk/res/android"
03
android:id
=
"@+id/top_search_bar"
04
android:layout_width
=
"match_parent"
05
android:layout_height
=
"45dip"
06
android:background
=
"@drawable/search_bar_bg"
07
android:visibility
=
"visible"

>
08
<
AutoCompleteTextView
09
android:id
=
"@+id/auto_search"
10
android:layout_width
=
"fill_parent"
11
android:layout_height
=
"wrap_content"
12
android:layout_centerVertical
=
"true"
13
android:layout_marginLeft
=
"5dip"
14
android:layout_marginRight
=
"5dip"
15
android:background
=
"@drawable/search_bar_edit_normal"
16
android:completionThreshold
=
"1"
17
android:drawableLeft
=
"@drawable/search_bar_icon_normal"
18
android:dropDownHorizontalOffset
=
"30dip"
19
android:dropDownVerticalOffset
=
"9dip"
20
android:dropDownWidth
=
"210dip"
21
android:singleLine
=
"true"
22
android:textSize
=
"15sp"

/>
23
24
<
ImageView
25
android:id
=
"@+id/iv_search_clear"
26
android:layout_width
=
"wrap_content"
27
android:layout_height
=
"wrap_content"
28
android:layout_alignParentRight
=
"true"
29
android:layout_centerVertical
=
"true"
30
android:layout_marginRight
=
"12dip"
31
android:layout_marginTop
=
"-1dip"
32
android:background
=
"@drawable/btn_search_clear_selector"

/>
33
34
</
RelativeLayout
>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: