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、在ListViewAdapter初始化时,将对象中有关CheckBox是否选中的属性存储起来。
查看源码
打印?
2、去掉CheckBox的holder.checkbox.setOnCheckedChangeListener(){}事件监听器
3、在Adapter里的publicViewgetView(finalintposition,ViewconvertView,ViewGroupparent){}方法体里面,当前的CheckBox是否选中状态,由之前初始化时保存的对象属性值控制,代码如下:
查看源码
打印?
3、用户点击ListView的Item时,改变CheckBox的状态,代码如下:
查看源码
打印?
数据适配器ListViewAdapter的完整代码:
查看源码
打印?
Activity中onCreate()里的写法:
查看源码
打印?
SearchToolbar类的代码:
查看源码
打印?
top_search_toolbar.xml文件:
查看源码
打印?
现在的问题是,当在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
0 ;i<size;i++){ |
4 | selectedMap.put(i,mPersons.get(i).isSelected()); |
5 | } |
3、在Adapter里的publicViewgetView(finalintposition,ViewconvertView,ViewGroupparent){}方法体里面,当前的CheckBox是否选中状态,由之前初始化时保存的对象属性值控制,代码如下:
1 | boolean
|
2 | holder.checkbox.setChecked(selected); |
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 | }); |
001 | package
|
002 |
003 | import
|
004 | import
|
005 |
006 | import
|
007 | import
|
008 | import
|
009 | import
|
010 | import
|
011 | import
|
012 | import
|
013 | import
|
014 | import
|
015 | import
|
016 |
017 | import
|
018 | import
|
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
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
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 | } |
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()); |
01 | package
|
02 | import
|
03 | import
|
04 | import
|
05 | import
|
06 | import
|
07 | import
|
08 | import
|
09 | import
|
10 | import
|
11 | import
|
12 |
13 | import
|
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 | } |
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 > |
相关文章推荐
- Android 中使用ListView和CheckBox进行批量操作
- 完美解决Android在listview添加checkbox实现批量操作问题
- Android ListView和CheckBox应用之批量删除操作
- 解决Android在listview中checkbox批量操作问题
- Android在listview添加checkbox实现批量操作问题
- 解决Android在listview中checkbox批量操作问题
- Android 中使用ListView和CheckBox进行批量操作
- Android ListView 使用checkbox 实现 单选、多选操作
- Android ListView和CheckBox应用之批量删除操作
- ListView使用Android提供的进行单选多选
- 无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)
- Android实现便于批量操作可多选的图片ListView实例
- 完美解决Android在listview添加checkbox实现单选多选操作问题
- android项目 之 来电管家(2) ----- ListView+CheckBox的使用
- 【Android开发新手的学习笔记】使用LruCache对ListView进行优化
- Android四大组件之—— 使用服务进行后台操作
- 【Android】Retrofit的使用(4)-Retrofit进行简单的GET和POST访问操作
- 解决Android在listview添加checkbox实现单选多选操作问题
- Android实现可多选的图片ListView,便于批量操作
- Android中ListView中使用CheckedTextView和CheckBox的理解