[英]Strange behaviour of checkBox in the listView
我有一個帶listView的片段,該listview布局包含(TextView,checkBox和ImageView如下)
t1........CB.......IV
t2........CB.......IV
t3........CB.......IV
t4........CB.......IV
t5........CB.......IV
t6........CB.......IV
SaveButton
在getView()方法中,我檢查該復選框是否已選中,如果已選中,則將選中的項目添加到列表中。
問題是,最初我將所有復選框都設置為未選中,但是當我選中第一項時,令人驚訝的是,下面的第三項被自動選中,如果我選中了上面的第二項,那么下面的第二項是檢查,如果我從上面檢查了第三項,那么最后一項會自動檢查?
請看一下getView()方法,讓我知道我錯過了什么:
getView() :
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if (convertView == null) {
LayoutInflater layoutinflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = layoutinflater.inflate(R.layout.list_items_layout, null);
}
if (this.checkedItemsList == null) {
this.checkedItemsList = new ArrayList<String>();
}
final TextView tv = (TextView) convertView.findViewById(R.id.tvlist_topic);
final CheckBox cb = (CheckBox) convertView.findViewById(R.id.cbList_hook);
final ImageView iv = (ImageView) convertView.findViewById(R.id.ivList_delete);
tv.setText(this.topicsList.get(position));
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
checkedItemsList.add(topicsList.get(position));
setCheckedItemsList(checkedItemsList);
Log.d(TAG, "size: " + checkedItemsList.size());
}
}
});
iv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (cb.isChecked())
cb.setChecked(false);
topicsList.remove(position);
notifyDataSetChanged();
}
});
return convertView;
}
xml :
<RelativeLayout
android:id="@+id/rl2_List"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/rl1_List"
android:layout_centerInParent="true">
<CheckBox
android:id="@+id/cbList_hook"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:checked="false"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl3_List"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/rl2_List"
android:layout_alignParentEnd="true"
android:layout_marginStart="100dp">
<ImageView
android:id="@+id/ivList_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="true"
android:src="@drawable/delete_icon"
android:contentDescription="icon to delete item from the Listview"/>
</RelativeLayout>
您必須保持對象檢查狀態。
我將在您的對象中(在topicList中)實現一個實例變量,該變量指示是否選中了該變量。
就像是
public class Topic{
public boolean isChecked;
... //Other instance variables
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
}
...
//other getters and setters
}
然后在您的listAdapter getView
方法中,檢查此值並相應地設置復選框。
final CheckBox cb = (CheckBox) convertView.findViewById(R.id.cbList_hook);
boolean isChecked = topicsList.get(position).isChecked();
cb.setChecked(isChecked);
//Set a tag on the cb, to know which object it corresponds with
cb.setTag(topicsList.get(position));
另外,單擊對象時必須更改其檢查值。
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
checkedItemsList.add(topicsList.get(position));
setCheckedItemsList(checkedItemsList);
Log.d(TAG, "size: " + checkedItemsList.size());
}
CheckBox cb = (CheckBox) buttonView;
Object yourObject = (Object) buttonView.getTag();
yourObject.setChecked(isChecked);
}
});
您需要了解convertView
,對於初學者而言,這通常會更加令人困惑。
例如,如果您在一個巨大的列表中有100個Checkbox,但是一次只能在屏幕上看到5個,那么天真的方法是為Checkbox創建100個對象(實際上,這是在早期版本的Android中的工作方式)。 但是,創建新對象不僅會在創建過程中消耗CPU資源,而且還會在垃圾回收過程中消耗CPU資源。 這就是為什么要使用convertView的原因。 Android系統將僅創建5個對象,並在用戶滾動時重復使用相同的對象。 就您而言,我認為屏幕上只有3個對象。 因此,從技術上講,滾動出屏幕的第一個對象和顯示在屏幕上的第四個對象是相同的。
您的解決方案是將View
對象視為可視元素,然后將狀態保存在其他位置。 我認為另一個答案是建議代碼,因此,我將避免建議代碼,並鼓勵您理解概念並自己找到解決方案。
你必須做這樣的事情
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if (convertView == null) {
LayoutInflater layoutinflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = layoutinflater.inflate(R.layout.list_items_layout, null);
}
if (this.checkedItemsList == null) {
this.checkedItemsList = new ArrayList<String>();
}
final TextView tv = (TextView) convertView.findViewById(R.id.tvlist_topic);
final CheckBox cb = (CheckBox) convertView.findViewById(R.id.cbList_hook);
final ImageView iv = (ImageView) convertView.findViewById(R.id.ivList_delete);
tv.setText(this.topicsList.get(position));
cb.setTag(position);
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
checkedItemsList.add(topicsList.get(Integer.parseInt(buttonView.getTag().toString())));
setCheckedItemsList(checkedItemsList);
Log.d(TAG, "size: " + checkedItemsList.size());
}
}
});
return convertView;
}
如果使用ViewHolder模式會更好。 這樣可以防止每次用戶滾動列表時都增加視圖的開銷。 另外,數據源(您要用來填充ListView的數據結構;在本例中為topicList)中是否應該存在一個復選框。 假設數據結構的模型類名為Model:
public class Model {
private boolean mChecked = false;
public boolean isChecked() {
return this.mChecked;
}
public void setChecked(boolean checked) {
this.mChecked = checked;
}
}
現在在ListView的適配器類中
public class SomeAdapter extends BaseAdapter {
private ArrayList<Model> topicsList; //assuming this is filled with data
static class ViewHolder { //the view holder's class
TextView text;
CheckBox checkBox;
ImageView imageView;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
if (convertView == null) {
LayoutInflater layoutinflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = layoutinflater.inflate(R.layout.list_items_layout, null);
TextView tv = (TextView) convertView.findViewById(R.id.tvlist_topic);
CheckBox cb = (CheckBox) convertView.findViewById(R.id.cbList_hook);
ImageView iv = (ImageView) convertView.findViewById(R.id.ivList_delete);
holder = new ViewHolder();
holder.textView = tv;
holder.checkBox = cb;
holder.imageView = iv;
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) converView.getTag();
}
if (this.checkedItemsList == null) {
this.checkedItemsList = new ArrayList<String>();
}
TextView textView = viewHolder.textView;
CheckBox checkBox = viewHolder.checkBox;
ImageView imageView = viewHolder.imageView;
textView.setText(this.topicsList.get(position));
if (this.topicsList.get(position).isChecked()) {
checkBox.setChecked(true);
} else {
checkBox.setChecked(false);
}
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
SomeAdapter.this.topicsList.get(position).setChecked(isChecked);
checkedItemsList.add(SomeAdapter.this.topicsList.get(position));
setCheckedItemsList(checkedItemsList);
Log.d(TAG, "size: " + checkedItemsList.size());
}
}
});
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (checkBox.isChecked()) {
checkBox.setChecked(false);
SomeAdapter.this.topicsList.get(position).setChecked(false);
topicsList.remove(position);
notifyDataSetChanged();
} else { //if needed
checkBox.setChecked(true);
SomeAdapter.this.topicsList.get(position).setChecked(true);
//perform other operations here
}
}
});
return convertView;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.