ListView 自定义适配器内的复选框
Checkbox inside ListView 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 个问题:第 1、2、3 行的复选框...绑定到第 8、9、10 行的复选框...所以每当我取消选中复选框 1 时,向下滚动到复选框 8,他也未选中,反之亦然。
我想这与视图持有者有关,它没有正确回收复选框,并且对第 1 行和第 8 行使用相同的复选框。有什么解决这个问题的建议吗?
convertView
in getView
以前用过 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;
}
}
ListView
在 getView()
方法中回收它的视图。添加这两个方法解决:
public int getViewTypeCount() {
return getCount();
}
@Override
public int getItemViewType(int position) {
return position;
}
这是我的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 行使用相同的复选框。有什么解决这个问题的建议吗?
convertView
in getView
以前用过 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;
}
}
ListView
在 getView()
方法中回收它的视图。添加这两个方法解决:
public int getViewTypeCount() {
return getCount();
}
@Override
public int getItemViewType(int position) {
return position;
}