Reputation: 2720
In my simple adapater, I want to manage checkboxes on items. When I click on a check box I change a status and when I'm scrolling the checkbox status is false and i can't fix my code to resolve this problem
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.CustomContactsViewHolder> {
private OnCardClickListener onCardClickListener;
private List<UserPhoneContacts> list = Collections.emptyList();
private Context context;
private Realm realm;
public static OnSelectedContacts onSelectedContacts;
private Map<String, Boolean> checkBoxStates = new HashMap<>();
public ContactsAdapter(List<UserPhoneContacts> list, Context context) {
this.list = list;
this.context = context;
this.realm = Realm.getDefaultInstance();
}
@Override
public CustomContactsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_item, parent, false);
CustomContactsViewHolder holder = new CustomContactsViewHolder(v);
return holder;
}
@Override
public void onBindViewHolder(final CustomContactsViewHolder holder, final int position) {
holder.contact_name.setText(list.get(position).getDisplayName());
holder.contact_mobile.setText(list.get(position).getMobileNumber());
Boolean checkedState = checkBoxStates.get(list.get(position).getMobileNumber());
holder.select_contact.setChecked(checkedState == null ? false : checkedState);
holder.select_contact.setTag(position);
holder.select_contact.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onChange((Integer) v.getTag());
}
});
}
private void onChange(int position) {
final UserPhoneContacts item = list.get(position);
if (item == null) {
return;
}
boolean checkedState = checkBoxStates.get(list.get(position).getMobileNumber()) != null;
checkBoxStates.put(item.getMobileNumber(), !checkedState);
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return list.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public void setData(List<UserPhoneContacts> list) {
this.list = list;
}
public static class CustomContactsViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.contact_name)
TextView contact_name;
@BindView(R.id.contact_mobile)
TextView contact_mobile;
@BindView(R.id.contact_photo)
CircleImageView contact_photo;
@BindView(R.id.select_contact)
CheckBox select_contact;
CustomContactsViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
}
}
what happen when i clicking on checkbox?
click->checked, click->unchecked, click-> unchecked, click-> unchecked, click-> unchecked
after unchecked checkbox i can't change checkbox state after that by click on that
Upvotes: 3
Views: 2370
Reputation: 3632
Here I made your CustomContactsViewHolder class as non static class, and did some changes regarding click events and setting data again to check and uncheck, once check with full code by taking your code as a backup.
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.CustomContactsViewHolder> {
private OnCardClickListener onCardClickListener;
private List<UserPhoneContacts> list = Collections.emptyList();
private Context context;
private Realm realm;
public static OnSelectedContacts onSelectedContacts;
private Map<String, Boolean> checkBoxStates = new HashMap<>();
public ContactsAdapter(List<UserPhoneContacts> list, Context context) {
this.list = list;
this.context = context;
this.realm = Realm.getDefaultInstance();
}
@Override
public CustomContactsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_item, parent, false);
CustomContactsViewHolder holder = new CustomContactsViewHolder(v);
return holder;
}
@Override
public void onBindViewHolder(final CustomContactsViewHolder holder, final int position) {
holder.contact_name.setText(list.get(position).getDisplayName());
holder.contact_mobile.setText(list.get(position).getMobileNumber());
boolean checkedState = checkBoxStates.containsKey(list.get(position).getMobileNumber())?checkBoxStates.get(list.get(position).getMobileNumber()):false;
holder.select_contact.setChecked(checkedState);
}
@Override
public int getItemCount() {
return list.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public void setData(List<UserPhoneContacts> list) {
this.list = list;
}
public class CustomContactsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@BindView(R.id.contact_name)
TextView contact_name;
@BindView(R.id.contact_mobile)
TextView contact_mobile;
@BindView(R.id.contact_photo)
CircleImageView contact_photo;
@BindView(R.id.select_contact)
CheckBox select_contact;
CustomContactsViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
@OnClick(R.id.select_contact)
@Override
public void onClick(View v) {
int position = getAdapterPosition();
switch (v.getId()){
case R.id.select_contact:
final UserPhoneContacts item = list.get(position);
if (item == null) {
return;
}
boolean checkedState = checkBoxStates.containsKey(list.get(position).getMobileNumber())?checkBoxStates.get(list.get(position).getMobileNumber()):false;
((CheckBox)v).setChecked(!checkedState);
checkBoxStates.put(item.getMobileNumber(), !checkedState);
ContactsAdapter.this.notifyDataSetChanged();
break;
}
}
}
}
Upvotes: 1
Reputation: 86
The leading cause of your problem is onChange method.
private void onChange(int position) {
final UserPhoneContacts item = list.get(position);
if (item == null) {
return;
}
boolean checkedState = checkBoxStates.get(list.get(position).getMobileNumber()) != null;
checkBoxStates.put(item.getMobileNumber(), !checkedState);
notifyDataSetChanged();
}
For example, firstly you click position 3 item, checkBoxStates.get(3) return null
, so !checkedState
will be true.
Secondly you click position 3, checkBoxStates.get(3) == True
, checkedState = (True != null) = true
, so !checkedState
will false.
Thirdly you click position 3, checkBoxStates.get(3) == False
, checkedState = (False != null) = true
, so !checkedState
also will false, the new state will also be unchecked.
The fixed code should be as following:
private void onChange(int position) {
final UserPhoneContacts item = list.get(position);
if (item == null) {
return;
}
Boolean lastCheckedState = checkBoxStates.get(list.get(position).getMobileNumber());
boolean checkedState = (null == lastCheckedState) ? false : lastCheckedState;
checkBoxStates.put(item.getMobileNumber(), !checkedState);
notifyDataSetChanged();
}
Upvotes: 0
Reputation: 5190
You don't need to create a separate Map<String, Boolean>
list to maintain whether your CheckBox
is selected or not. Try the simple trick below. But you need to update your UserPhoneContacts
model class as follows.
public class UserPhoneContacts {
// other variables
private boolean isSelected = false; // add this
// your class constructor and other getter/setter methods
// add below getter method
public boolean isSelected() {
return this.isSelected;
}
// add below setter method
public void setSelected(boolean isSelected) {
this.isSelected = isSelected;
}
}
Change your ContactAdapter
class like this
@Override
public void onBindViewHolder(final CustomContactsViewHolder holder, final int position) {
...
final UserPhoneContacts upc = list.get(position);
holder.select_contact.setChecked(upc.isSelected() ? true : false);
holder.select_contact.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
upc.setSelected(!upc.isSelected());
holder.view.setChecked(upc.isSelected() ? true : false);
}
});
}
Upvotes: 1