i have a BaseAdapter for my ListView inside a fragment that looks like this:
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;
}
}
i have 20 list items, and the problem is that when i checked first 2 items for example at index [0] and [1], somehow it also checked automatically other items at index [9] and [10] when i scroll down the list. same case happened if i checked other items and it will checked repeatedly with the same pattern every time i scroll down the list.
i actually dont know what's happening, so i want to ask if anyone here can stop this messy. Thank you!
Your Custom Adapter must implement CompoundButton.OnCheckedChangeListener. Use a SparseBooleanArray.
Then
cb.setChecked(mCheckStates.get(position, false)); // cb is checkbox
cb.setOnCheckedChangeListener(this);
Then use the checked state to set text to check box
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);
}
Discussion on the topic @
https://groups.google.com/forum/?fromgroups#!topic/android-developers/No0LrgJ6q2M
Example:
Use a ViewHolder. The below example does not use a View Holder.
There is a Button at the bottom of the screen. When you check the check boxes items of the checked rows are displayed in a toast when you click the button at the bottom.
Use the below and modify according to your requirements.
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);
}
}
}
I'm currently using solution provided here: ListView with CheckBox Scrolling Issue
it works for me and i change my adapter class like this:
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;
}
}
i use 2 arraylists to keep the data: first, for all data and the second for the data that the user currently searching. so, while the user is typing to search by keywords the check state are passed between the first and the second arraylist resulting in the persistence checked items no matter what position they're.
but thanks for raghunandan, your answer is my corner stone to reach a better solution!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With