我的listview遇到了一些小问题。每个项目都有一些信息和一个复选框。这显示正常,我可以选择和取消选中复选框等等。
但是我发现了一些奇怪的行为。假设我单击第一行的第一个复选框。如果ListView很小,所以你不需要向下滚动这个工作正常。但是如果ListView很大,所以我需要向下滚动才能看到所有项目,底部的一些随机项也会被点击。 相反的行为,如果我单击列表视图底部的复选框并向上滚动,也会在顶部单击一些随机复选框。如果我点击某个地方的几个复选框,其他一些地方有相同数量的点击复选框。我想这会在调用GetView(...)时发生,这意味着它会更新。然后点击一些新的复选框,但我不知道为什么。
在这里感谢一些帮助! :)
我的适配器的SSSCE:
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;
}
}
答案 0 :(得分:3)
如上所述,问题是您没有在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;
}
}
答案 1 :(得分:2)
答案 2 :(得分:1)
问题可能与您在适配器中处理回收视图的方式有关。看一下你的getView
并检查你返回的每个项目的CheckBox是否根据其“模型”正确设置。
编辑:我确认。您必须像设置textview的文本一样设置复选框状态。 顺便说一下,我觉得按照你的方式处理Checkbox是一个坏主意。你可以做的最好的事情是为复选框定义一个“模型”(iE:一个简单的boolean []可以做到这一点),避免实例化太多的CheckBoxes。在你的getView中,你可以检查相应的布尔值并相应地设置复选框。
为了检查/取消选中它们,您可以修改checkAllBoxes中的布尔数组,然后调用notifyDatasetChanged(),在列表视图上触发更新,但仅对实际显示的项进行操作:)
答案 3 :(得分:1)
mr_archano是对的,这是因为你使用convertView,它允许你重新使用/回收不再在视图中的视图。以下是您需要正确执行的操作:
保存每个复选框状态的对象
由于您的列表视图项目正在被回收,因此您无法依赖它们来保持复选框的正确状态。因此,您需要某种对象/数组来保存每个列表项的复选框的正确状态。
从州管理对象中读取
然后,当您调用GetView时,您必须根据该对象/数组的状态将复选框的值设置为选中/取消选中。
写入状态管理对象
您需要为每个复选框实现某种OnChecked侦听器,以便您可以在语句管理对象/数组中正确设置该复选框的值。
您应该尝试使用ViewHolder的
ViewHolder非常简单。首次创建视图(不使用转换视图)时,必须调用“FindViewByID”以获取对文本框和复选框的引用。如果将它们保存在ViewHolder中,则应该能够在使用ConvertView对象时直接引用它们,这将节省对“FindViewByID”的额外调用。它看起来更容易实践。
本教程几乎可以满足您的需求:http://windrealm.org/tutorials/android/listview-with-checkboxes-without-listactivity.php
答案 4 :(得分:0)
处理大型列表时遇到同样的问题。对于喜欢我的人来说,通过Google找到这里,我想提供我的解决方案,我认为这更容易理解。正如大家指出的那样,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;
}
});
您需要以自己的方式保持已选中/未选中状态。