ListView之checkbox錯(cuò)位問(wèn)題解決
本節(jié)引言:
作為L(zhǎng)istView經(jīng)典問(wèn)題之一,如果你嘗試過(guò)自定義ListView的item,在上面帶有一個(gè)checkbox的話,那么 當(dāng)你的item數(shù)超過(guò)了一頁(yè)的話,就會(huì)出現(xiàn)這個(gè)問(wèn)題,下面我們來(lái)分析下出現(xiàn)這種問(wèn)題的原因,以及如何來(lái) 解決這個(gè)問(wèn)題!
1.問(wèn)題發(fā)生的原因:
這是網(wǎng)上找來(lái)的一幅關(guān)于ListView getView方法調(diào)用機(jī)制的一個(gè)圖
上圖中有一個(gè)Recycler的東東,平時(shí)我們ListView上可見的Item處于內(nèi)存中,而且他的Item則放在 這個(gè)Recycler中,第一次加載item時(shí),當(dāng)前頁(yè)面中的convertView都為NULL,當(dāng)滾出屏幕,這是時(shí)候ConvertView不為空,所以新的一項(xiàng)會(huì)復(fù)用這個(gè)ConvertView! 我們可以寫個(gè)簡(jiǎn)單的例子,跟下log,下面是運(yùn)行后的一些Log圖!
從圖中看出,Postion從12開始,ConvertView就不為空了,具體這里代表的是什么, 我也不知道,目測(cè)要走源碼...我們知道這里ConvertView會(huì)緩存就好,就是因?yàn)檫@個(gè)原因 造成的checkbox錯(cuò)位,所以第一個(gè)解決方式就是,不重用這個(gè)ConvertView,或者 說(shuō)每次getView都將這個(gè)ConvertView設(shè)置為null,但是如果需要顯示的Item數(shù)目巨大的話, 這種方法就會(huì)顯得非常臃腫,一般實(shí)際開發(fā)我們使用的是下面的解決方法:找個(gè)東東來(lái)保存當(dāng)前Item CheckBox的狀態(tài),初始化的時(shí)候進(jìn)行判斷,設(shè)置是否選中!
2.解決方法示例:
好的存儲(chǔ)這個(gè)Checkbox的方法有很多,你可以放到一個(gè)HashMap<Integer, Boolean>中, 每次初始化的時(shí)候根據(jù)postion取出對(duì)應(yīng)的boolean值,然后再進(jìn)行checkbox的狀態(tài)設(shè)置; 而筆者的做法則是在entity類中加入了一個(gè)boolean值用于判斷,下面是筆者一個(gè)項(xiàng)目中 抽取出來(lái)的代碼,代碼比較簡(jiǎn)單,相信你看完會(huì)秒懂的~
Entity類:Person.java:
private String name;
private String number;
private boolean checkStatus;
public Person(String name, String number) {
super();
this.name = name;
this.number = number;
this.checkStatus = false;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public boolean getCheckStatus() {
return checkStatus;
}
public void setCheckStatus(boolean checkStatus) {
this.checkStatus = checkStatus;
}
}
實(shí)現(xiàn)的Adapter類:ContactListAdapter.java:
private List<Person> mData;
private Context mContext;
public ContactListAdapter(List<Person> data, Context context) {
mData = data;
mContext = context;
}
// 定義一個(gè)刷新數(shù)據(jù)的方法
public void changeData(List<Person> data) {
mData = data;
notifyDataSetChanged();
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Person getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int index = position;
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.item_contact, parent, false);
viewHolder = new ViewHolder();
viewHolder.ly = (RelativeLayout) convertView
.findViewById(R.id.lyContactListItem);
viewHolder.txtName = (TextView) convertView
.findViewById(R.id.txtName);
viewHolder.txtNumber = (TextView) convertView
.findViewById(R.id.txtNumber);
viewHolder.cbxStatus = (CheckBox) convertView
.findViewById(R.id.cbxStatus);
convertView.setTag(viewHolder);
viewHolder.cbxStatus.setTag(index);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.cbxStatus.setOnCheckedChangeListener(this);
viewHolder.cbxStatus.setChecked(mData.get(position).getcheckStatus());
viewHolder.txtName.setText(mData.get(index).getName());
viewHolder.txtNumber.setText(mData.get(index).getNumber());
return convertView;
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int index = (int)buttonView.getTag();
if (isChecked)
mData.get(index).setCheckStatus(true);
else
mData.get(index).setCheckStatus(false);
}
private class ViewHolder {
RelativeLayout ly;
TextView txtName;
TextView txtNumber;
CheckBox cbxStatus;
}
}
嘿嘿,非常簡(jiǎn)單,另外別忘了一點(diǎn):checkbox監(jiān)聽器的方法要添加在初始化Checkbox狀態(tài)的代碼之前哦~
本節(jié)引言:
好的,本節(jié)給大家講解了ListView的一個(gè)經(jīng)典問(wèn)題,ListView中checkbox錯(cuò)位的 問(wèn)題解決,只需簡(jiǎn)單的添加一個(gè)記錄checkbox選擇狀態(tài)的值,然后重寫checkbox 點(diǎn)擊事件的時(shí)候,先做判斷~謝謝~