滚动自定义 ListView 时,复选框值发生变化
Posted
技术标签:
【中文标题】滚动自定义 ListView 时,复选框值发生变化【英文标题】:When scrolling custom ListView, the checkbox value changes 【发布时间】:2012-07-05 19:47:30 【问题描述】:我有什么:一个带有文本视图和复选框的自定义列表视图。
问题:假设我的屏幕一次只能显示 6 项列表,而其他项是不可见的。 所以我检查了列表中的第一个元素(位置 0 的项目)。我向下滚动以查看我的所有列表,当我向上滚动第一个元素(位置 0 的项目)时,复选框被正确选中。伟大的!但是现在也检查了新项目,例如位置 8 的项目(因为当我滚动列表(对于 theRycicking)它成为位置 0 的新项目..记住我的屏幕一次只显示 7 个元素)。它被检查了,但我从未检查过!
问题:我怎样才能避免这个问题?我不希望我不单击的复选框更改其状态。
在我实现 setOnCheckedChangeListener 的带有 getView 函数的 listView 适配器下方:
public class NewQAAdapterSelectFriends extends BaseAdapter
private LayoutInflater mInflater;
private Person[] data;
public NewQAAdapterSelectFriends(Context context)
mInflater = LayoutInflater.from(context);
public void setData(Person[] data)
this.data = data;
@Override
public int getCount()
return data.length;
@Override
public Object getItem(int item)
return data[item];
@Override
public long getItemId(int position)
return position;
@Override
public View getView(final int position, View convertView, ViewGroup parent)
if (convertView == null)
convertView = mInflater.inflate(R.layout.item_select_friends, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
viewHolder.nameText.setTag(viewHolder.nameText);
viewHolder.nameText.setTag(viewHolder.surnameText);
viewHolder.contactImage.setTag(data[position]);
viewHolder.checkBox.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked)
Person element = (Person) viewHolder.checkBox.getTag();
if(isChecked)
element.setCheck(buttonView.isChecked());
//data[position].setCheck(true); //this is equivalent to previous line
else
//to-do
);
viewHolder.checkBox.setTag(data[position]);
else
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.nameText.setText(data[position].getName());
holder.surnameText.setText(data[position].getSurname());
holder.contactImage.setImageResource(data[position].getPhotoRes());
holder.contactImage.setScaleType(ScaleType.FIT_XY);
holder.checkBox.setChecked(data[position].isCheck());
return convertView;
static class ViewHolder
TextView nameText;
TextView surnameText;
ImageView contactImage;
CheckBox checkBox;
感谢您的回答:)
编辑:根据建议,我改变了我的 getView,如下所示:
@Override
public View getView(final int position, View convertView, ViewGroup parent)
final ViewHolder viewHolder;
if (convertView == null)
convertView = mInflater.inflate(R.layout.item_select_friends, null);
viewHolder=new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
viewHolder.nameText.setTag(viewHolder.nameText);
viewHolder.nameText.setTag(viewHolder.surnameText);
viewHolder.contactImage.setTag(data[position]);
viewHolder.checkBox.setChecked(data[position].isCheck());
viewHolder.checkBox.setOnClickListener(new OnClickListener()
public void onClick(View arg0)
if(viewHolder.checkBox.isChecked()==true)
data[position].setCheck(true);
else
data[position].setCheck(false);
);
else
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.nameText.setText(data[position].getName());
viewHolder.surnameText.setText(data[position].getSurname());
viewHolder.contactImage.setImageResource(data[position].getPhotoRes());
viewHolder.contactImage.setScaleType(ScaleType.FIT_XY);
viewHolder.checkBox.setChecked(data[position].isCheck());
return convertView;
编辑后的情况:现在,如果我检查屏幕上显示的初始项目,然后滚动列表,则它们的值已正确保存。但是当我滚动列表时,例如我想检查列表的最后一个树复选框,然后在我滚动后它们变得未选中....但是为什么??????
已解决:我用以下代码解决了 getView 的问题:
public class NewQAAdapterSelectFriends extends BaseAdapter
private LayoutInflater mInflater;
private Person[] data;
boolean[] checkBoxState;
ViewHolder viewHolder;
public NewQAAdapterSelectFriends(Context context)
mInflater = LayoutInflater.from(context);
public void setData(Person[] data)
this.data = data;
checkBoxState=new boolean[data.length];
@Override
public int getCount()
return data.length;
@Override
public Object getItem(int item)
return data[item];
@Override
public long getItemId(int position)
return position;
@Override
public View getView(final int position, View convertView, ViewGroup parent)
if (convertView == null)
convertView = mInflater.inflate(R.layout.item_select_friends, null);
viewHolder=new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
else
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.nameText.setText(data[position].getName());
viewHolder.surnameText.setText(data[position].getSurname());
viewHolder.contactImage.setImageResource(data[position].getPhotoRes());
viewHolder.contactImage.setScaleType(ScaleType.FIT_XY);
viewHolder.checkBox.setChecked(checkBoxState[position]);
viewHolder.checkBox.setOnClickListener(new View.OnClickListener()
public void onClick(View v)
if(((CheckBox)v).isChecked())
checkBoxState[position]=true;
data[position].setCheck(true);
else
checkBoxState[position]=false;
data[position].setCheck(false);
);
return convertView;
static class ViewHolder
TextView nameText;
TextView surnameText;
ImageView contactImage;
CheckBox checkBox;
我已经看过这个教程来做我的getView:http://androidcocktail.blogspot.it/2012/04/adding-checkboxes-to-custom-listview-in.html
【问题讨论】:
很好的解决方案,它对我有用 只有一个问题?什么是 Person[] 数据?我的意思是它看起来怎么样? 唯一对我有用的解决方案。 如果用户更改开关而不是单击而不是简单的小拖动会怎样? :P 【参考方案1】:您没有涵盖convertView != null 的情况,这是上下滚动时发生的情况。您应该实现一种方法来回收 convertView(更好)或忽略它并在这种情况下也返回一个新的 View(更糟)。
【讨论】:
【参考方案2】:仅当 convertview 为空时,您才设置复选框的标记。这只发生在记录的第一个屏幕上。当用户向下滚动时,之前的转换视图被回收。因此,您的复选框将旧数据项作为其标签。
您检查的更改侦听器应如下所示:
new CompoundButton.OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked)
Person element = (Person) viewHolder.checkBox.getTag();
data[position].setCheck(isChecked);
if(isChecked)
// do your stuff
else
//to-do
【讨论】:
谢谢你的回答,但我不工作。现在,如果我在滚动列表时检查了一些复选框,我会丢失更改并且每个复选框都未选中!!!我也会尝试添加: if(isChecked) data[position].setChecked(true) else data[position].setChecked(false) ...我该怎么办??? DON"T 使用 onCheckedChanged,改用 onClick,这对我有用。【参考方案3】:检查此代码
public class NewQAAdapterSelectFriends extends BaseAdapter
private LayoutInflater mInflater;
private Person[] data;
ArrayList<String> checkedItem=new ArrayList<String>();
public NewQAAdapterSelectFriends(Context context)
mInflater = LayoutInflater.from(context);
public void setData(Person[] data)
this.data = data;
@Override
public int getCount()
return data.length;
@Override
public Object getItem(int item)
return data[item];
@Override
public long getItemId(int position)
return position;
@Override
public View getView(final int position, View convertView, ViewGroup parent)
if (convertView == null)
convertView = mInflater.inflate(R.layout.item_select_friends, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
viewHolder.nameText.setTag(viewHolder.nameText);
viewHolder.nameText.setTag(viewHolder.surnameText);
viewHolder.contactImage.setTag(data[position]);
viewHolder.checkBox.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked)
Person element = (Person) viewHolder.checkBox.getTag();
if(isChecked)
getCheckList(data[position],isChecked);
else
getCheckList(data[position],isChecked);
);
viewHolder.checkBox.setTag(data[position]);
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.nameText.setText(data[position].getName());
holder.surnameText.setText(data[position].getSurname());
holder.contactImage.setImageResource(data[position].getPhotoRes());
holder.contactImage.setScaleType(ScaleType.FIT_XY);
if(checkedItem != null && checkedItem.contains(data[position]))
viewHolder.checkBox.setChecked(true);
else
viewHolder.checkBox.setChecked(false);
return convertView;
static class ViewHolder
TextView nameText;
TextView surnameText;
ImageView contactImage;
CheckBox checkBox;
public void getCheckList(String value,boolean status)
if(!checkedItem.contains(value) && status)
checkedItem.add(value);
if(checkedItem.contains(value) && !status)
checkedItem.remove(value);
【讨论】:
我尝试了您的解决方案,但是当我单击复选框然后滚动复选框时,所有复选框都变得未选中......为什么??? 这个逻辑对我有用。检查checkedItem 的值或发布应用此逻辑的更改代码。 您好,我将代码更改为您的答案。我使用了相同的代码,但复选框失去了它们的价值:(.. 如果这不起作用,请告诉我您的电子邮件 ID,我将向您发送演示应用程序。 谢谢...我的电子邮件是 ciavarellastefano89@gmail.com ...我正在等待您的申请 :)【参考方案4】:检查下面的代码-
public View getView(int position, View convertView, ViewGroup parent)
View view = convertView;
ViewHolder holder = new ViewHolder();
if(view == null)
view = inflater.inflate(R.layout.list_callcycle_blue, null);
holder.llContainer = (LinearLayout) view.findViewById(R.id.ll_container);
holder.lblLabel = (TextView) view.findViewById(R.id.txt_desc);
holder.cb = (CheckBox) view.findViewById(R.id.cb_store);
view.setTag(holder);
else
holder = (ViewHolder) view.getTag();
final Object data = getItem(position);
holder.lblLabel.setText(data.getDescription());
holder.cb.setTag(position);
holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
int position = (Integer) buttonView.getTag();
objects.get(position).setChecked(buttonView.isChecked());
);
holder.cb.setChecked(isChecked(position));
return view;
永远记住,在设置数据之前使用 change holder.cb.setOnCheckedChangeListener()
即任何监听器,在我们的例子中是holder.cb.setChecked()
原因: 当我们滚动时,listview 会回收视图,所以如果 setchecked 在侦听器之前使用,那么它将在旧侦听器的基础上选择值。如果我们在监听器之后设置它,那么它将采用最新值
【讨论】:
主要帮助您解释将设置值放在设置侦听器之后的原因。【参考方案5】:我解决了我的问题,只是将“setOnCheckedChangeListener”更改为“setOnClickListener”
public View getView(final int position, View convertView, ViewGroup parent)
ViewHolder holder;
if (convertView == null)
CheckBox cbItemChecklist = new CheckBox(context);
holder = new ViewHolder();
holder.cbItemChecklist = cbItemChecklist;
convertView = cbItemChecklist;
convertView.setTag(holder);
else
holder = (ViewHolder) convertView.getTag();
final ItemChecklist itemChecklist = itensChecklist.get(position);
holder.cbItemChecklist.setText(itemChecklist
.getDescricaoItemChecklist());
holder.cbItemChecklist.setChecked(itemChecklist.isChecked());
holder.cbItemChecklist
.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
if(itemChecklist.isChecked())
itemChecklist.setChecked(false);
else
itemChecklist.setChecked(true);
);
return convertView;
【讨论】:
【参考方案6】:我有一个不错的 CheckBox 替代品。您可以将 android:state_activated="true"
用于您的 ListView 行。它不会丢失状态,也不需要大量代码。
这里是如何工作的
在您的可绘制文件夹中创建active_row.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true"
android:drawable="@android:color/darker_gray"/>
</selector>
将行布局的背景设置为android:background="@drawable/active_row.xml"
最后将它添加到您的 ListView
android:choiceMode="multipleChoice"
你可以像这样检查每一行的状态
View v;
LinearLayout yourRowLayout;
for (int i = 0; i < yourListView.getChildCount(); i++)
v = yourListView.getChildAt(i);
yourRowLayout = (LinearLayout) v.findViewById(R.id. yourRowLayout);
if(yourRowLayout.isActivated())....
【讨论】:
【参考方案7】:在适配器中使用 setTag()。您可以在此处查看示例Example listview with checkbox scroll issue
【讨论】:
【参考方案8】:您需要更新适配器以保留复选框的值
holder.chk.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
CheckBox c = (CheckBox)v.findViewById(R.id.chkID);
Boolean chk = c.isChecked();
Integer pos = (Integer)v.getTag();
itemList.get(pos).setChk(chk);
);
如需更多帮助,请参阅Retain Checkbox value 中的此帖子
【讨论】:
以上是关于滚动自定义 ListView 时,复选框值发生变化的主要内容,如果未能解决你的问题,请参考以下文章
UIButton 状态在滚动带有多个部分的 tableview 时发生变化 - Swift
TableView 滚动时自定义 UITableViewCell 发生变化