listView中checkBox的奇怪行为

时间:2015-02-02 11:53:49

标签: android listview checkbox android-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()方法中,我检查是否选中了复选框,如果选中它,我将选中的项添加到列表中。

问题在于,最初我将所有复选框设置为未选中,但是当我检查第一项时,令人惊讶的是,自动检查下面的第三项,如果我从上面检查第二项,则第二项从下面检查,如果我检查上面的第3项,然后自动检查最后一项?!!

请查看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>

4 个答案:

答案 0 :(得分:1)

您必须保持对象检查状态。

我会在你的对象(在topicsList中)实现一个实例变量,它指示是否检查过它。

这样的东西
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);
    }
});

答案 1 :(得分:0)

您需要了解convertView,这对初学者来说往往更加困惑。

例如,如果您在一个巨大的列表中有100个复选框,但屏幕上一次只能看到5个,那么天真的方法是为Checkbox创建100个对象(实际上这是它在早期版本的Android中的工作方式) 。但是,创建新对象不仅会在创建过程中耗费CPU,还会在垃圾收集期间耗费CPU。这就是使用convertView的原因。 Android系统将仅创建5个对象,并在用户滚动时重用相同的对象。在您的情况下,我认为屏幕上只有3个对象。因此,从技术上讲,滚出屏幕的第一个对象和屏幕上显示的第四个对象是相同的。

您的解决方案是将View个对象视为可视元素,并将状态保存在其他位置。我认为另一个答案建议代码,因此,我将避免建议代码并鼓励您理解这个概念并自己找出解决方案。

答案 2 :(得分:0)

你必须做这样的事情

@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;
}

答案 3 :(得分:0)

如果使用ViewHolder模式会更好。每次用户滚动列表时,它将防止膨胀视图的开销。此外,是否应选中复选框应存在于数据源中(用于填充ListView的数据结构;在本例中为topicsList)。假设数据结构的模型类名为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;
 }
}