原本以為已經把ListView搞的滿熟的了,沒想到今天要在自訂畫面的ListView中加一個CheckBox竟然搞了快四個小時才搞完它
雖然只是需要改動adapter中的一點點東西,但一直以為是自已元件用不熟,出了錯誤,一直在找自已錯在哪裡找不出來,實在是很痛苦
最後的錯誤在於:
若在自訂義ListView的情況下,如果設定了ListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)
在item中若只有CheckedTextView的話就沒事,但若是自已訂議了有被包起來的CheckBox就會出事
網上的討論似乎是跟Android資源回收利用時會把View給刪掉再重開有關系
所以在這情況下,如果要使用onItemClickListener 或onListItemClick時,回傳的position會沒錯,可是position所對應的View會亂跳
每次按都不一定會回給你哪一個View。完完整整的亂掉,更有時候按一按就當掉了。
解決方法很簡單,只要把創造出來的每一個CheckBox都另外存起來 hold住,不讓系統回收掉就好了。
我參考了幾篇之中,以下這一篇寫的比較好:
http://www.itivy.com/android/archive/2011/12/14/android-listview-checkbox-problem.html
所以就以此篇作為基礎,自已寫了一個可以放入CheckBox的SimpleCursorAdapter供大家使用。
(寫完之後才發現原來我自已是要用CursorAdapter,只需依照相似的作法即可)
開一個新的class,將下面的東西放入,然後就可以呼叫著用了~!
比較不一樣的地方是,如果有CheckBox的部分,要將CheckBox的id放入 CheckBoxID欄位中,才會對應到。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
abstract public class SimpleCheckedCursorAdapter extends BaseAdapter{
private boolean[] isSelected;
private Context context = null;
private LayoutInflater inflater = null;
private Cursor cursor = null;
private int resource = 0;
private String keyString[] = null;
private String itemString = null;
private int idValue[] = null;// id
private int checkboxID = 0;
public class ViewHolder {
public CheckBox cb = null;
}
public SimpleCheckedCursorAdapter(Context context, Cursor cursor,
int resource, String[] from, int[] to, int checkboxID) {
this.context = context;
this.cursor = cursor;
this.resource = resource;
keyString = new String[from.length];
idValue = new int[to.length];
System.arraycopy(from, 0, keyString, 0, from.length);
System.arraycopy(to, 0, idValue, 0, to.length);
this.checkboxID = checkboxID;
inflater = LayoutInflater.from(context);
init();
}
public void init() {
cursor.moveToFirst();
isSelected = new boolean[getCount()];
Arrays.fill(isSelected, Boolean.FALSE);
}
public void toggle(View v, int pos){
ViewHolder holder = (ViewHolder) v.getTag();
holder.cb.toggle();
isSelected[pos] = holder.cb.isChecked();
}
public long[] getCheckedItemIDs(){
List<Long> CheckedIDs = new ArrayList<Long>();
for(int i =0;i<isSelected.length;i++){
if(isSelected[i]){
cursor.moveToPosition(i);
CheckedIDs.add(cursor.getLong(cursor.getColumnIndex("_id")));
}
}
long[] IDs = new long[CheckedIDs.size()];
for(int i=0;i<CheckedIDs.size();i++){
IDs[i]=CheckedIDs.get(i);
}
return IDs;
}
@Override
public int getCount() {
cursor.moveToFirst();
return cursor.getCount();
}
@Override
public Object getItem(int pos) {
return null;
}
@Override
public long getItemId(int pos) {
return cursor.getLong(cursor.getColumnIndex("_id"));
}
@Override
public View getView(int position, View view, ViewGroup arg2) {
cursor.moveToPosition(position);
ViewHolder holder = null;
if (holder == null) {
holder = new ViewHolder();
if (view == null) {
view = inflater.inflate(resource, null);
}
for(int i=0;i<idValue.length;i++){
View v = view.findViewById(idValue[i]);
itemString = cursor.getString(cursor.getColumnIndex(keyString[i]));
if(v instanceof TextView){
TextView tv = (TextView) v;
tv.setText(itemString);
}else if(v instanceof EditText){
EditText et = (EditText) v;
et.setText(itemString);
}else if(v instanceof Button){
Button btn = (Button) v;
btn.setText(itemString);
}else if (v instanceof CheckBox){
CheckBox cb =(CheckBox) v;
if(itemString.contentEquals("1")||itemString.contentEquals("0")){
cb.setChecked(itemString.contains("1"));
}else{
cb.setText("itemString[i]");
}
}
}
holder.cb = (CheckBox) view.findViewById(checkboxID);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.cb.setChecked(isSelected[position]);
return view;
}
}

請問你在以下是怎樣修改呢? lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView> arg0, View view, int position, long arg3) { ViewHolder holder = (ViewHolder) view.getTag(); holder.cb.toggle();// 在每次获取点击的item时改变checkbox的状态 MyAdapter.isSelected.put(position, holder.cb.isChecked()); // 同时修改map的值保存状态 if (holder.cb.isChecked() == true) { listStr.add(name[position]); } else { listStr.remove(name[position]); } tv.setText("已选中"+listStr.size()+"项"); } });
我將這邊的onItemClickListener拆解後放到 toggle 與 getCheckedItemIDs 中了 在外部使用這個CursorAdapter時,若要改變某一個cb的值,只要在onItemClickListener中使用toggle即會反轉,若要查詢有哪些cb被勾選了,則用getCheckedItemIDs。