Android 具有多个复选框的ListView适配器
我的listview有一些小问题。每个项目都有一些信息和一个复选框。这显示良好,我可以选择和取消选择复选框等 然而,我发现了一些奇怪的行为。假设我单击第一行的第一个复选框。如果ListView很小,因此您不需要向下滚动,那么这很好。但是如果ListView很大,所以我需要向下滚动以查看所有项目,那么底部的一些随机项目也会被单击。 同样的行为反过来说,如果我单击listview底部的复选框并向上滚动,一些随机复选框也会在顶部单击。如果我在某个地方单击了几个复选框,那么在其他地方单击的复选框数量相同。我想当GetView。。。被调用,意思是当它更新时。然后它会点击一些新的复选框,但我不知道为什么 感谢您的帮助!: 我的适配器的SSSCE:Android 具有多个复选框的ListView适配器,android,listview,checkbox,xamarin.android,listview-adapter,Android,Listview,Checkbox,Xamarin.android,Listview Adapter,我的listview有一些小问题。每个项目都有一些信息和一个复选框。这显示良好,我可以选择和取消选择复选框等 然而,我发现了一些奇怪的行为。假设我单击第一行的第一个复选框。如果ListView很小,因此您不需要向下滚动,那么这很好。但是如果ListView很大,所以我需要向下滚动以查看所有项目,那么底部的一些随机项目也会被单击。 同样的行为反过来说,如果我单击listview底部的复选框并向上滚动,一些随机复选框也会在顶部单击。如果我在某个地方单击了几个复选框,那么在其他地方单击的复选框数量相同
public class ListViewAdapterSSCCE : BaseAdapter
{
private Activity myActivity;
private string[] someData;
private int numberOfElements;
private CheckBox[] boxes;
public ListViewAdapterSSCCE(Activity activity)
{
this.myActivity = activity;
for (int i = 0; i < numberOfElements; i++)
this.boxes[i] = new CheckBox(myActivity);
}
public void SetData(string[] someData)
{
this.someData = someData;
this.numberOfElements = someData.Length;
}
public void CheckAllBoxes(bool isChecked)
{
for (int i = 0; i < numberOfElements; i++)
this.boxes[i].Checked = isChecked;
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 10;
}
public override int Count
{
get { return numberOfElements; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
LayoutInflater inflater = (LayoutInflater)myActivity.GetSystemService(Context.LayoutInflaterService);
convertView = inflater.Inflate(Resource.Layout.ChildrenList_item, null);
}
var itemBox = convertView.FindViewById<CheckBox>(Resource.Id.checkbox);
this.boxes[position] = itemBox;
var textView = convertView.FindViewById<TextView>(Resource.Id.item_data);
textView.Text = this.someData[position];
return convertView;
}
}
问题可能与适配器中处理回收视图的方式有关。查看您的getView并检查您返回的每个项目的复选框是否根据其“模型”正确设置 编辑:我确认。您必须像设置textview文本一样设置复选框状态。 顺便说一句,我认为用你现在的方式处理复选框是个坏主意。您可以做的最好的事情是为复选框定义一个模型,即:一个简单的布尔[]可以做到这一点,避免实例化太多的复选框。在getView中,可以选中相应的布尔值并相应地设置复选框
为了选中/取消选中所有复选框,您可以修改复选框中的布尔数组,然后调用notifyDatasetChanged,触发listview上的更新,但只对实际显示的项目进行操作:您可以在此处看到示例代码,以对复选框状态进行替代修复: 如果这篇文章对你有帮助,请将这篇文章标记为答案
谢谢。如前所述,问题是您没有在getView中设置复选框值 此外,您还可以大大提高代码的效率。您应该做的第一件事是将复选框添加到子视图xml中,而不是创建它们的数组。而是创建一个布尔数组来存储值 注意,我正在修改这一点,就像我在Java中所做的那样,因此在C中可能需要更改一些东西
public class ListViewAdapterSSCCE : BaseAdapter
{
private string[] someData;
private int numberOfElements;
private boolean[] checkValue;
private LayoutInflater inflater;
public ListViewAdapterSSCCE(Context context)
{
inflater = LayoutInflater.from(context);
}
public void SetData(string[] someData)
{
this.someData = someData;
this.numberOfElements = someData.Length;
}
public void CheckAllBoxes(bool isChecked)
{
for (int i = 0; i < numberOfElements; i++)
checkValue[i] = true;
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 10;
}
public override int Count
{
get { return numberOfElements; }
}
public override View GetView(final int position, View convertView, ViewGroup parent)
{
final ViewHolder holder;
if (convertView == null)
{
convertView = inflater.Inflate(Resource.Layout.ChildrenList_item, null);
holder = new ViewHolder();
holder.itemBox = convertView.FindViewById<CheckBox>(Resource.Id.checkbox);
holder.textView = convertView.FindViewById<TextView>(Resource.Id.item_data);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
itemBox = checkValue[position];
itemBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
checkValue[positon] = isChecked;
}
});
textView.Text = this.someData[position];
return convertView;
}
class ViewHolder
{
CheckBox itemBox;
TextView textView;
}
}
阿查诺先生是对的,这是因为您使用的是convertView,它允许您重用/回收不再在视图中的视图。以下是正确执行此操作所需的内容: 用于保存每个复选框状态的对象 因为您的listview项目正在被回收,所以您不能依靠它们来保持复选框的正确状态。因此,您需要某种对象/数组来保存每个列表项的复选框的正确状态 从状态管理对象读取 然后,在调用GetView时,必须根据对象/数组的状态将复选框的值设置为选中/未选中 写入状态管理对象 您需要为每个复选框实现某种类型的OnChecked侦听器,以便在语句管理对象/数组中正确设置该复选框的值 您应该尝试使用ViewHolder的 ViewHolder非常简单。第一次创建视图时不使用convert View,必须调用FindViewByID以获取对文本框和复选框的引用。如果将它们保存在ViewHolder中,则在使用ConvertView对象时应该能够直接引用它们,这将保存对FindViewByID的其他调用。看它练习起来容易多了
本教程提供了您所需要的功能:我在处理大型列表时也遇到了同样的问题。对于像我一样通过谷歌在这里找到的人,我想给出我的解决方案,我认为这更容易理解。正如guys所指出的,ListView重用了视图。因此,您不应该让视图保存您的数据状态 我使用SimpleAdapter,通过设置自定义的ViewBinder,我发现很容易解决这个问题
listItemAdapter.setViewBinder(new SimpleAdapter.ViewBinder() {
public boolean setViewValue(View view, Object obj, String s) {
if(view instanceof CheckBox){
((CheckBox)view).setChecked((Boolean)obj);
return true;
}
return false;
}
});
您需要以自己的方式保持检查/未检查状态。我一看到您的答案就明白了问题所在!我想应该是这样的。感谢您的解释,也是一个很好的解决方案!感谢您的进一步和更透彻的解释!从阿卡诺出生起就给他答案看起来很棒!在他编辑之前看到archanos的帖子后,我也在想类似的事情,但是你把它写在纸上了,非常感谢!事实上,经过一些测试,这种方法是不合法的。问题是,当复选框滚动到看不见的地方时,会调用onCheckedChanged。因此,它的状态不会被保存。我选择使用OnClick,正如Joey answer中的链接所示。