带有复选框的自定义 ListView 检查未选中的项目
Posted
技术标签:
【中文标题】带有复选框的自定义 ListView 检查未选中的项目【英文标题】:custom ListView with checkboxes checking unchecked items 【发布时间】:2013-09-02 16:49:06 【问题描述】:我的 ListView 有一个 BaseAdapter,位于片段中,如下所示:
public class SelectionMucListAdapter extends BaseAdapter
private LayoutInflater inflater = null;
Typeface titleFace;
ArrayList<UsersData> innerList = new ArrayList<UsersData>();
public SelectionMucListAdapter(ArrayList<UsersData> users)
inflater = (LayoutInflater) mainActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
titleFace = Typeface.createFromAsset(mainActivity.getAssets(), "fonts/bradybun.ttf");
innerList = users;
@Override
public int getCount()
return innerList.size();
@Override
public Object getItem(int position)
return position;
@Override
public long getItemId(int id)
return id;
@Override
public View getView(final int position, View convertView, ViewGroup parent)
ViewHolder viewHolder;
if (convertView == null)
convertView = inflater.inflate(R.layout.muc_list_item, null);
viewHolder = new ViewHolder();
viewHolder.image = (ImageView)convertView.findViewById(R.id.item_image);
viewHolder.check = (CheckBox)convertView.findViewById(R.id.cb_choose_user);
viewHolder.title = (TextView)convertView.findViewById(R.id.item_text_1);
viewHolder.rating=(RatingBar)convertView.findViewById(R.id.item_text_2);
convertView.setTag(viewHolder);
else
viewHolder = (ViewHolder)convertView.getTag();
viewHolder.title.setTypeface(titleFace);
Bitmap avatar = innerList.get(position).getUserAvatar();//UsersManager.getInstance().getUsers().get(position).getUserAvatar();
if(avatar != null)
viewHolder.image.setImageBitmap(avatar);
viewHolder.title.setText(innerList.get(position).getUserName());
viewHolder.rating.setRating((float)Double.parseDouble(innerList.get(position).getRating()));
viewHolder.check.setOnCheckedChangeListener(new OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton cb, boolean isChecked)
if(cb.isChecked()) // if this item is checked then add to list
Log.v("CheckBox", "pos: "+position+" checked");
if(!choices.contains(innerList.get(position)))
choices.add(innerList.get(position));
else // if its unchecked then remove from list if exist
Log.v("CheckBox", "pos: "+position+" checked");
if(choices.contains(innerList.get(position)))
choices.remove(innerList.get(position));
isChecked = cb.isChecked();
);
viewHolder.check.setTag(position);
return convertView;
static class ViewHolder
ImageView image;
CheckBox check;
TextView title;
RatingBar rating;
class CheckState
boolean isChecked;
UsersData usersData;
public UsersData getUsersData()
return usersData;
public void setUsersData(UsersData usersData)
this.usersData = usersData;
public boolean isChecked()
return isChecked;
public void setChecked(boolean isChecked)
this.isChecked = isChecked;
我有 20 个列表项,问题是当我检查前 2 个项目时,例如在索引 [0] 和 [1] 处,不知何故,当我检查索引 [9] 和 [10] 处的其他项目时向下滚动列表。如果我检查其他项目也会发生同样的情况,并且每次我向下滚动列表时它都会以相同的模式重复检查。
我实际上不知道发生了什么,所以我想问一下这里是否有人可以阻止这种混乱。谢谢!
【问题讨论】:
当您单击列表视图时打印项目。 请查看此链接,它很有帮助.. lalit3686.blogspot.in/2012/06/… 【参考方案1】:您的自定义适配器必须实现CompoundButton.OnCheckedChangeListener
。使用SparseBooleanArray.
然后
cb.setChecked(mCheckStates.get(position, false)); // cb is checkbox
cb.setOnCheckedChangeListener(this);
然后使用选中状态将文本设置为复选框
public boolean isChecked(int position)
return mCheckStates.get(position, false);
public void setChecked(int position, boolean isChecked)
mCheckStates.put(position, isChecked);
public void toggle(int position)
setChecked(position, !isChecked(position));
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked)
mCheckStates.put((Integer) buttonView.getTag(), isChecked);
话题@讨论
https://groups.google.com/forum/?fromgroups#!topic/android-developers/No0LrgJ6q2M
例子:
使用ViewHolder
。下面的例子没有使用 View Holder。
屏幕底部有一个按钮。当您选中复选框时,当您单击底部的按钮时,选中的行的项目会显示在吐司中。
使用以下内容并根据您的要求进行修改。
public class MainActivity extends Activity implements
AdapterView.OnItemClickListener
int count;
private CheckBoxAdapter mCheckBoxAdapter;
String[] GENRES = new String[]
"Action", "Adventure", "Animation", "Children", "Comedy",
"Documentary", "Drama",
"Foreign", "History", "Independent", "Romance", "Sci-Fi",
"Television", "Thriller"
;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ListView listView = (ListView) findViewById(R.id.lv);
listView.setItemsCanFocus(false);
listView.setTextFilterEnabled(true);
listView.setOnItemClickListener(this);
mCheckBoxAdapter = new CheckBoxAdapter(this, GENRES);
listView.setAdapter(mCheckBoxAdapter);
Button b= (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
// TODO Auto-generated method stub
StringBuilder result = new StringBuilder();
for(int i=0;i<mCheckBoxAdapter.mCheckStates.size();i++)
if(mCheckBoxAdapter.mCheckStates.get(i)==true)
result.append(GENRES[i]);
result.append("\n");
Toast.makeText(MainActivity.this, result, 1000).show();
);
public void onItemClick(AdapterView parent, View view, int
position, long id)
mCheckBoxAdapter.toggle(position);
class CheckBoxAdapter extends ArrayAdapter implements CompoundButton.OnCheckedChangeListener
private SparseBooleanArray mCheckStates;
LayoutInflater mInflater;
TextView tv1,tv;
CheckBox cb;
String[] gen;
CheckBoxAdapter(MainActivity context, String[] genres)
super(context,0,genres);
mCheckStates = new SparseBooleanArray(genres.length);
mInflater = (LayoutInflater)MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
gen= genres;
@Override
public int getCount()
// TODO Auto-generated method stub
return gen.length;
@Override
public Object getItem(int position)
// TODO Auto-generated method stub
return position;
@Override
public long getItemId(int position)
// TODO Auto-generated method stub
return 0;
@Override
public View getView(final int position, View convertView, ViewGroup parent)
// TODO Auto-generated method stub
View vi=convertView;
if(convertView==null)
vi = mInflater.inflate(R.layout.checkbox, null);
tv= (TextView) vi.findViewById(R.id.textView1);
cb = (CheckBox) vi.findViewById(R.id.checkBox1);
tv.setText("Name :"+ gen [position]);
cb.setTag(position);
cb.setChecked(mCheckStates.get(position, false));
cb.setOnCheckedChangeListener(this);
return vi;
public boolean isChecked(int position)
return mCheckStates.get(position, false);
public void setChecked(int position, boolean isChecked)
mCheckStates.put(position, isChecked);
public void toggle(int position)
setChecked(position, !isChecked(position));
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked)
mCheckStates.put((Integer) buttonView.getTag(), isChecked);
【讨论】:
不需要任何 SparseBooleanArray。您需要做的就是向适配器使用的数据模型添加一个布尔字段 @pskink 我是从 Romain Guy 的 Android 开发者小组的解决方案中挑选出来的。如果您有替代解决方案,请发布相同的内容。对于发布的解决方案,您需要SparseBooleanArray
OP的解决方案正如我所说,他需要在他的UsersData数据模型中添加一个布尔字段,在getView方法中进行适当的映射,当然还要在CheckBox监听器中更新这个字段【参考方案2】:
我目前正在使用此处提供的解决方案: ListView with CheckBox Scrolling Issue
它对我有用,我像这样更改我的适配器类:
public class SelectionMucListAdapter extends ArrayAdapter<Model>
private final FragmentActivity context;
Typeface titleFace;
ArrayList<Model> innerList
= new ArrayList<Model>();
boolean checkAll_flag = false;
boolean checkItem_flag = false;
public SelectionMucListAdapter(FragmentActivity context
, ArrayList<Model> users)
super(context, R.layout.muc_list_item, users);
this.context = context;
titleFace = Typeface.createFromAsset
(mainActivity.getAssets(), "fonts/bradybun.ttf");
this.innerList = users;
@Override
public View getView(final int position, View convertView, ViewGroup parent)
ViewHolder viewHolder = null;
if (convertView == null)
LayoutInflater inflator = context.getLayoutInflater();
convertView = inflator.inflate(R.layout.muc_list_item, null);
viewHolder = new ViewHolder();
viewHolder.image = (ImageView) convertView.findViewById(R.id.item_image);
viewHolder.title = (TextView) convertView.findViewById(R.id.item_text_1);
viewHolder.title.setTypeface(titleFace);
viewHolder.rating= (RatingBar) convertView.findViewById(R.id.item_text_2);
viewHolder.check = (CheckBox) convertView.findViewById(R.id.cb_choose_user);
viewHolder.check.setOnCheckedChangeListener(new OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
// TODO Auto-generated method stub
int getPosition = (Integer) buttonView.getTag(); // Here we get the position that we have set for the checkbox using setTag.
innerList.get(getPosition).setSelected(buttonView.isChecked()); // Set the value of checkbox to maintain its state.
users.get(innerList.get(getPosition).getTrueIndex()).setSelected(buttonView.isChecked());
);
convertView.setTag(viewHolder);
convertView.setTag(R.id.item_image, viewHolder.image);
convertView.setTag(R.id.item_text_1, viewHolder.title);
convertView.setTag(R.id.item_text_2, viewHolder.rating);
convertView.setTag(R.id.cb_choose_user, viewHolder.check);
else
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.check.setTag(position); // This line is important.
viewHolder.title.setText(innerList.get(position).getData().getUserName());
viewHolder.rating.setRating((float)
Double.parseDouble(innerList.get(position).getData().getRating()));
viewHolder.check.setChecked(innerList.get(position).isSelected());
Bitmap avatar = innerList.get(position).getData().getUserAvatar();
if(avatar != null)
viewHolder.image.setImageBitmap(avatar);
return convertView;
class ViewHolder
ImageView image;
CheckBox check;
TextView title;
RatingBar rating;
我使用 2 个数组列表来保存数据:第一个用于所有数据,第二个用于用户当前搜索的数据。因此,当用户输入关键字进行搜索时,检查状态会在第一个和第二个数组列表之间传递,从而导致持久性检查项,无论它们在什么位置。
但感谢 raghunandan,您的回答是我达成更好解决方案的基石!
【讨论】:
【参考方案3】:这里的技巧是使用一个布尔数组,其中 size() = listview 项目的数量。目的是标记选择了哪些项目,哪些没有。当你检查一个项目时,根据它的位置更新它的状态。希望这对您有所帮助。 :)
【讨论】:
【参考方案4】:除了@Raghunandan answer,Android 会在滚动时重用 listview 中的视图,这样当您滚动列表视图时,最后一个离开屏幕的视图就是下一个视图会从另一边进入屏幕,所以如果选中1和2,滚动后选中9和10,这可能意味着屏幕上同时显示了8个项目,这样第九个项目android系统使用第一个的视图,所以它会检查。
【讨论】:
【参考方案5】:我认为这在我的 xml 中对您很有用,我正在使用 textview 和复选框。使用 getView() 方法,就像我已经实现并使用 bean 类在活动和适配器之间进行通信一样。
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter
Context context;
ArrayList list;
LayoutInflater inflator;
public MyAdapter(Context context,ArrayList list)
this.context=context;
this.list=list;
inflator=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@Override
public int getCount()
// TODO Auto-generated method stub
return list.size();
@Override
public Object getItem(int position)
// TODO Auto-generated method stub
return list.get(position);
@Override
public long getItemId(int position)
// TODO Auto-generated method stub
return 0;
public class ViewHolder
ImageView imageView;
TextView name;
TextView mob;
CheckBox check;
public ViewHolder(View v)
imageView=(ImageView) v.findViewById(R.id.imageView1);
name=(TextView) v.findViewById(R.id.textView1);
mob=(TextView) v.findViewById(R.id.textView2);
check=(CheckBox) v.findViewById(R.id.checkBox1);
@Override
public View getView(final int position, View convertView, ViewGroup parent)
// TODO Auto-generated method stub
View vi=convertView;
ViewHolder holder;
final Contacts contacts=(Contacts) list.get(position);
if(convertView==null)
vi=inflator.inflate(R.layout.contacts, null);
holder=new ViewHolder(vi);
vi.setTag(holder);
else
holder=(ViewHolder) vi.getTag();
holder.imageView.setImageBitmap(contacts.getImage());
holder.name.setText(contacts.getName());
holder.mob.setText(contacts.getNumber());
holder.check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
contacts.setCheck(isChecked);
notifyDataSetChanged();
);
holder.check.setChecked(contacts.isCheck());
return vi;
【讨论】:
如果有人对实施有任何疑问,请询问 什么是最终联系人 contacts=(Contacts) list.get(position);?以上是关于带有复选框的自定义 ListView 检查未选中的项目的主要内容,如果未能解决你的问题,请参考以下文章
使用android中的自定义arrayadapter在listview中使用复选框检查后如何删除多个项目?
滚动后未选中 ListView 适配器中的 Android 复选框