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

来源:互联网 发布:淘宝售后率怎么算 编辑:程序博客网 时间:2024/05/18 03:41

在使用ListView时,一般为了性能的提升,都会使用ViewHolder,也就是Item的View实现复用。

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

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

?
1
2
3
4
5
6
7
8
holder.checkbox.setOnCheckedChangeListener(newOnCheckedChangeListener() {
 
            @Override
            publicvoidonCheckedChanged(CompoundButton buttonView, booleanisChecked) {
                driver.setSelected(isChecked);
            }
 
        });

解决办法:

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

?
1
2
3
4
5
selectedMap = newHashMap<Integer, Boolean>();
      intsize = mPersons.size();
      for(inti = 0; i < size; i++) {
          selectedMap.put(i, mPersons.get(i).isSelected());
      }

2、去掉CheckBox的holder.checkbox.setOnCheckedChangeListener(){}事件监听器

3、在Adapter里的 public View getView(final int position, View convertView, ViewGroup parent){}方法体里面,当前的CheckBox是否选中状态,由之前初始化时保存的对象属性值控制,代码如下:

?
1
2
booleanselected = selectedMap.get(position);
holder.checkbox.setChecked(selected);

3、用户点击ListView的Item时,改变CheckBox的状态,代码如下:

?
1
2
3
4
5
6
7
8
9
convertView.setOnClickListener(newView.OnClickListener() {
 
           @Override
           publicvoidonClick(View v) {
               checkbox.toggle();
               selectedMap.put(position, checkbox.isChecked());
               driver.setSelected(checkbox.isChecked());
           }
       });

数据适配器ListViewAdapter的完整代码:

?
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
packagecom.easipass.cloud.ccp.adapter;
 
importjava.util.ArrayList;
importjava.util.HashMap;
 
importandroid.content.Context;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.widget.BaseAdapter;
importandroid.widget.CheckBox;
importandroid.widget.Filter;
importandroid.widget.Filterable;
importandroid.widget.ImageView;
importandroid.widget.TextView;
 
importcom.easipass.R;
importcom.easipass.cloud.ccp.entity.UserInfo;
 
/**
 * 用户列表数据适配器
 *
 * @author android_ls
 */
publicfinalclass UserListViewAdapter extendsBaseAdapter implementsFilterable {
    privateLayoutInflater inflater;
 
    privateMyFilter myFilter;
 
    privatefinalObject mLock = newObject();
 
    privateArrayList<UserInfo> mPersons;
 
    privateArrayList<UserInfo> mCheckValues;
 
    publicHashMap<Integer, Boolean> selectedMap;
 
    publicUserListViewAdapter(Context context, ArrayList<UserInfo> cms) {
        inflater = LayoutInflater.from(context);
        mPersons = cms;
 
        selectedMap = newHashMap<Integer, Boolean>();
        intsize = mPersons.size();
        for(inti = 0; i < size; i++) {
            selectedMap.put(i, mPersons.get(i).isSelected());
        }
 
    }
 
    @Override
    publicintgetCount() {
        returnmPersons.size();
    }
 
    @Override
    publicObject getItem(intarg0) {
        returnmPersons.get(arg0);
    }
 
    @Override
    publiclonggetItemId(intposition) {
        returnposition;
    }
 
    @Override
    publicView getView(finalintposition, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if(convertView == null) {
            convertView = inflater.inflate(R.layout.ccp_carmanager_lv_item, null);
            holder = newViewHolder();
            holder.text1 = (TextView) convertView.findViewById(R.id.tv_name);
            holder.text2 = (TextView) convertView.findViewById(R.id.tv_phnoe);
            holder.checkbox = (CheckBox) convertView.findViewById(R.id.checkbox);
            holder.imageView = (ImageView) convertView.findViewById(R.id.iv_icon);
 
            convertView.setTag(holder);
        else{
            holder = (ViewHolder) convertView.getTag();
        }
 
        finalUserInfo driver = mPersons.get(position);
 
        holder.text1.setText(driver.getName());
 
        holder.text2.setText(driver.getPhoneNumber());
        // TODO 测试
        holder.imageView.setBackgroundResource(Integer.valueOf(driver.getIconUrl()));
        holder.checkbox.setVisibility(View.VISIBLE);
 
        booleanselected = selectedMap.get(position);
        holder.checkbox.setChecked(selected);
 
        finalCheckBox checkbox = holder.checkbox;
        convertView.setOnClickListener(newView.OnClickListener() {
 
            @Override
            publicvoidonClick(View v) {
                checkbox.toggle();
                selectedMap.put(position, checkbox.isChecked());
                driver.setSelected(checkbox.isChecked());
            }
        });
 
        if(selected) {
            convertView.setClickable(false);
        }
 
        returnconvertView;
    }
 
    @Override
    publicFilter getFilter() {
        if(myFilter == null) {
            myFilter = newMyFilter();
        }
        returnmyFilter;
    }
 
    classMyFilter extendsFilter {
 
        @Override
        protectedFilterResults performFiltering(CharSequence prefix) {
            FilterResults results = newFilterResults();
            if(mCheckValues == null) {
                synchronized(mLock) {
                    mCheckValues = newArrayList<UserInfo>(mPersons);
                }
            }
 
            if(prefix == null|| prefix.length() == 0) {
                synchronized(mLock) {
                    ArrayList<UserInfo> list = newArrayList<UserInfo>(mCheckValues);
                    results.values = list;
                    results.count = list.size();
                }
            else{
                String prefixString = prefix.toString().toLowerCase();
                finalArrayList<UserInfo> values = mCheckValues;
                finalintcount = values.size();
 
                finalArrayList<UserInfo> newValues = newArrayList<UserInfo>(count);
                for(inti = 0; i < count; i++) {
                    finalUserInfo value = (UserInfo) values.get(i);
                    if(value.getName().contains(prefixString)) {
                        newValues.add(value);
                    }
                }
 
                results.values = newValues;
                results.count = newValues.size();
            }
 
            returnresults;
        }
 
        @SuppressWarnings("unchecked")
        @Override
        protectedvoidpublishResults(CharSequence constraint, FilterResults results) {
            mPersons = (ArrayList<UserInfo>) results.values;
            if(results.count > 0) {
                notifyDataSetChanged();
            else{
                notifyDataSetInvalidated();
            }
        }
    }
 
    staticclassViewHolder {
        publicTextView text1;
 
        publicTextView text2;
 
        publicImageView imageView;
 
        publicCheckBox checkbox;
    }
 
}

Activity中onCreate()里的写法:

?
1
2
3
4
5
6
7
mSearchToolbar = (SearchToolbar) this.findViewById(R.id.top_search_toolbar);
   mListView = (ListView) this.findViewById(R.id.listview);
    
   mDriverListAdapter = newUserListViewAdapter(this, driverList);
   mListView.setAdapter(mDriverListAdapter);
 
   mSearchToolbar.setFilter(mDriverListAdapter.getFilter());

SearchToolbar类的代码:

?
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
packagecom.easipass.custom.view;
importandroid.content.Context;
importandroid.text.Editable;
importandroid.text.TextWatcher;
importandroid.util.AttributeSet;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.widget.AutoCompleteTextView;
importandroid.widget.FrameLayout;
importandroid.widget.ImageView;
importandroid.widget.RelativeLayout;
 
importcom.easipass.R;
 
/**
 * 功能描述:自定义搜索框组件
 * @author android_ls
 */
publicclassSearchToolbar extendsFrameLayout {
 
    privateRelativeLayout topSearchToolbar;
     
    /**
     * 顶部自动补全文本输入框
     */
    privateAutoCompleteTextView autoSearch;
 
    /**
     * 清除搜索结果按钮
     */
    privateImageView btnClearSearch;
     
    publicSearchToolbar(Context context) {
        super(context);
        setupViews();
    }
 
    publicSearchToolbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupViews();
    }
 
    privatevoidsetupViews() {
        finalLayoutInflater mLayoutInflater = LayoutInflater.from(getContext());
        topSearchToolbar = (RelativeLayout) mLayoutInflater.inflate(R.layout.top_search_toolbar, null);
        addView(topSearchToolbar);
         
        btnClearSearch = (ImageView) topSearchToolbar.findViewById(R.id.iv_search_clear);
        autoSearch = (AutoCompleteTextView) topSearchToolbar.findViewById(R.id.auto_search);
    }
     
    publicvoidsetFilter(final android.widget.Filter filter) {
        autoSearch.addTextChangedListener(newTextWatcher() {
 
            @Override
            publicvoidonTextChanged(CharSequence s, intstart, intbefore, intcount) {
                String filterWord = autoSearch.getText().toString().trim();
                filter.filter(filterWord);
            }
 
            @Override
            publicvoidbeforeTextChanged(CharSequence s, intstart, intcount, intafter) {
                // TODO Auto-generated method stub
 
            }
 
            @Override
            publicvoidafterTextChanged(Editable s) {
                // TODO Auto-generated method stub
 
            }
        });
 
        btnClearSearch.setOnClickListener(newView.OnClickListener() {
 
            @Override
            publicvoidonClick(View v) {
                autoSearch.setText(null);
            }
        });
    }
     
}

top_search_toolbar.xml文件:

?
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
29
30
31
32
33
34
<?xmlversion="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/top_search_bar"
    android:layout_width="match_parent"
    android:layout_height="45dip"
    android:background="@drawable/search_bar_bg"
    android:visibility="visible">
    <AutoCompleteTextView
        android:id="@+id/auto_search"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="5dip"
        android:layout_marginRight="5dip"
        android:background="@drawable/search_bar_edit_normal"
        android:completionThreshold="1"
        android:drawableLeft="@drawable/search_bar_icon_normal"
        android:dropDownHorizontalOffset="30dip"
        android:dropDownVerticalOffset="9dip"
        android:dropDownWidth="210dip"
        android:singleLine="true"
        android:textSize="15sp"/>
 
    <ImageView
        android:id="@+id/iv_search_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="12dip"
        android:layout_marginTop="-1dip"
        android:background="@drawable/btn_search_clear_selector"/>
 
</RelativeLayout>
0 0