ListView自定义适配器中的复选框

时间:2015-03-12 17:51:10

标签: android listview checkbox custom-adapter

这是我的custom_list.xml

<CheckBox
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/cb"
    android:layout_marginLeft="16dp"
    android:layout_gravity="center"
    android:checked="true" />

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/nameTV"
    android:layout_gravity="center"
    android:textSize="22sp"
    android:padding="16dp" />

这是我的CustomAdapter.java

private Context context;
private ArrayList<String> arrayList;
private CompoundButton.OnCheckedChangeListener onCheckedChangeListener;
private boolean[] mItemChecked;

public CustomAdapter(Context context, ArrayList<String> arrayList, CompoundButton.OnCheckedChangeListener onCheckedChangeListener) {
    this.context = context;
    this.arrayList = arrayList;
    this.onCheckedChangeListener = onCheckedChangeListener;
    mItemChecked = new boolean[arrayList.size()];
    for (int i=0; i<arrayList.size(); i++){
        mItemChecked[i] = true;
    }
}

private static class ViewHolder {
    TextView tv;
    CheckBox cb;
}

@Override
public int getCount() {
    return arrayList.size();
}

@Override
public Object getItem(int position) {
    return arrayList.get(position);
}

@Override
public long getItemId(int position) {
    return 0;
}

public boolean itemIsChecked(int position){
    return mItemChecked[position];
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final ViewHolder holder;
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    if (convertView == null) {
        convertView = inflater.inflate(R.layout.custom_list, parent, false);
        holder = new ViewHolder();
        holder.tv = (TextView) convertView.findViewById(R.id.nameTV);
        holder.cb = (CheckBox) convertView.findViewById(R.id.cb);
        convertView.setTag(holder);
    }else{
        holder = (ViewHolder) convertView.getTag();
    }
    holder.tv.setText(arrayList.get(position));
    holder.cb.setOnCheckedChangeListener(onCheckedChangeListener);
    return convertView;
}

虽然一切正常但有一个问题:第1,2,3行的复选框绑定到第8,9,10行的复选框......所以每当我取消选中复选框1并滚动时到复选框8,他也未经检查,反之亦然。 我想这是与视图持有者有关的东西,它没有正确地回收复选框,并且在第1行和第8行使用相同的复选框。有什么建议可以解决这个问题吗?

1 个答案:

答案 0 :(得分:-1)

convertView中的{p> getView以前使用过View以前的数据!因此,您需要每次在View中为getView填充正确的数据。在您的代码中,我不知道您在哪里设置了checkbox的状态。你应该这样做。与TextView holder.tv.setText(arrayList.get(position));

一样

<强>更新

这是代码示例。看看getView。其他诸如创建初始数据或数据结构等简化。

public class CustomAdapter extends BaseAdapter {

    private List<String> arrayList = new ArrayList<>(30);
    private boolean[] mItemChecked = new boolean[30];
    private Context mContext;

    public CustomAdapter(Context context) {
        mContext = context;
        for (int i = 0; i < 30; i++) {
            arrayList.add("text: " + i);
            mItemChecked[i] = false;
        }
    }

    public int getCount() {
        return arrayList.size();
    }

    @Override
    public Object getItem(int position) {
        return arrayList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    public boolean itemIsChecked(int position) {
        return mItemChecked[position];
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.list_item, parent, false);
            holder = new ViewHolder();
            holder.tv = (TextView) convertView.findViewById(R.id.nameTV);
            holder.cb = (CheckBox) convertView.findViewById(R.id.cb);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.tv.setText(arrayList.get(position));
        //Important to remove previous listener before calling setChecked
        holder.cb.setOnCheckedChangeListener(null);
        holder.cb.setChecked(mItemChecked[position]);
        holder.cb.setTag(position);
        holder.cb.setOnCheckedChangeListener(
                new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        mItemChecked[position] = isChecked;
                    }
                });
        return convertView;
    }

    private class ViewHolder {
        TextView tv;
        CheckBox cb;

    }
}

ListViewgetView()方式回收其视图。添加这两个方法来解决:

public int getViewTypeCount() {                 
    return getCount();
}

@Override
public int getItemViewType(int position) {
    return position;
}