【问题标题】:Checkbox inside ListView custom adapterListView 自定义适配器内的复选框
【发布时间】:2015-03-12 17:51:10
【问题描述】:

这是我的 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 个问题:第 1、2、3 行的复选框...绑定到第 8、9、10 行的复选框...所以每当我取消选中复选框 1 并滚动直到复选框 8,他也未被选中,反之亦然。 我猜这与视图持有者有关,它没有正确回收复选框,并且对第 1 行和第 8 行使用相同的复选框。有什么解决这个问题的建议吗?

【问题讨论】:

    标签: android listview checkbox custom-adapter


    【解决方案1】:

    getView 中的convertView 以前使用View 和以前的数据!所以你需要在getView 中每次都用正确的数据填写你的View。在您的代码中,我看不到您在哪里设置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;
    }
    

    【讨论】:

    • 是的,这就是我认为的问题所在,我只是找不到正确的方法。您是否知道即使在行滚动离开视图之后,我如何才能为每一行获得正确的复选框状态?
    • @Bimba 添加了代码示例。看看getView。请注意,其他事情被简化了。您应该自己选择合适的数据结构来存储数据。
    • 非常感谢兄弟,它确实解决了我的问题,但另一个问题随之而来......现在它不会在回收时保存复选框状态。因此,如果我选中其中一个复选框,而不是向下滚动,而不是向上滚动,它将保持未选中状态。
    • @Bimba 只需尝试提供的代码。复选框状态保存在mItemChecked 数组中。
    猜你喜欢
    • 2014-05-20
    • 2014-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多