How to fix Checkbox in RecyclerView when no solution works? - android

I'm trying to set up a checkbox in my recycler view, but I'm facing the common problem of random checks without my control. I check one item and some more random items are being checked at the same time.
I realise this is a common question here, but the solutions I found here don't seem to work. Among many others I was trying to follow different instructions in this thread:
Android RecyclerView checkbox checks itself
but what seems to be the problem is that functions isSelected and setSelected can't be resolved.
My best guess is that the reason for this complication might be that my onCheckedChange action is actually interfaced from the main activity, as you can see at the bottom of the code below. Is that what complicates the code (can't avoid it)?
public LocationRecyclerViewAdapter(List<IndividualLocation> styles,
Context context, ClickListener cardClickListener, OnCheckedChangeListener checkedChangeListener, int selectedTheme) {
this.context = context;
this.listOfLocations = styles;
this.selectedTheme = selectedTheme;
this.clickListener = cardClickListener;
this.onCheckedChangeListener = checkedChangeListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int singleRvCardToUse = R.layout.single_location_map_view_rv_card;
View itemView = LayoutInflater.from(parent.getContext()).inflate(singleRvCardToUse, parent, false);
return new ViewHolder(itemView);
}
public interface ClickListener {
void onItemClick(int position);
}
public interface OnCheckedChangeListener {
void onCheckboxClick(int position);
}
#Override
public int getItemCount() {
return listOfLocations.size();
}
#Override
public void onBindViewHolder(final ViewHolder card, int position) {
final IndividualLocation locationCard = listOfLocations.get(position);
card.nameTextView.setText(locationCard.getName());
card.addressTextView.setText(locationCard.getAddress());
card.hoursTextView.setText(locationCard.getHours());
card.priceTextView.setText(locationCard.getPrice());
card.categoryTextView.setText(locationCard.getCategory());
card.cuisineTextView.setText(locationCard.getCuisine());
card.happyHourTextView.setText(locationCard.getHappyHour());
card.lunchDealTextView.setText(locationCard.getLunchDeal());
card.websiteTextView.setText("WEBSITE");
card.newPlaceTextView.setText(locationCard.getNewPlace());
card.websiteTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String url = locationCard.getWebsite();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
context.startActivity(intent);
}
});
static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView nameTextView;
TextView addressTextView;
TextView priceTextView;
TextView hoursTextView;
TextView categoryTextView;
TextView cuisineTextView;
TextView happyHourTextView;
TextView lunchDealTextView;
TextView newPlaceTextView;
ConstraintLayout constraintUpperColorSection;
CardView cardView;
ImageView backgroundCircleImageView;
ImageView emojiImageView;
Button websiteTextView;
CheckBox checkBox;
ViewHolder(View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.location_name_tv);
addressTextView = itemView.findViewById(R.id.location_description_tv);
priceTextView = itemView.findViewById(R.id.location_price_tv);
hoursTextView = itemView.findViewById(R.id.location_hours_tv);
backgroundCircleImageView = itemView.findViewById(R.id.background_circle);
emojiImageView = itemView.findViewById(R.id.emoji);
constraintUpperColorSection = itemView.findViewById(R.id.constraint_upper_color);
categoryTextView = itemView.findViewById(R.id.location_type_tv);
cuisineTextView = itemView.findViewById(R.id.location_cuisine_tv);
happyHourTextView = itemView.findViewById(R.id.happyhour_tv);
lunchDealTextView = itemView.findViewById(R.id.lunchdeal_tv);
cardView = itemView.findViewById(R.id.map_view_location_card);
websiteTextView = itemView.findViewById(R.id.website);
newPlaceTextView = itemView.findViewById(R.id.new_place);
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
clickListener.onItemClick(getLayoutPosition());
}
});
checkBox = itemView.findViewById(R.id.checkBox);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
onCheckedChangeListener.onCheckboxClick(getLayoutPosition());
}
}});
}
#Override
public void onClick(View view) {
}
}
}
I'm sure there is some simple solution to this, but I've been cracking my head over this for way too long now. Thanks!

First of all, you have to check the checkbox programatically, for every item. Your model should hold the data, a simple boolean could do it.
The second is the trickiest one
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.isPressed()){
if (isChecked ) {
onCheckedChangeListener.onCheckboxClick(holder.getAdapterPosition()());
}}
}});
You have to check if the checkbox is actually checked, in order to avoid confusions,

Inside your onBindViewHolder you have to set your checkbox either checked or unchecked. if true, your checkbox will be selected, else unselected,
because recycler view will be recycled every time you scroll, so you need to make sure you need to tell adapter that checkbox need to be checked or unchecked at that particular position.

why are you using getLayoutPosition() for getting checkbox position
use like this holder.getAdapterPosition()
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
onCheckedChangeListener.onCheckboxClick(holder.getAdapterPosition()());
}
}});
and move this listener to your onBindViewHolder()

Your data model should have a boolean variable isChecked. You can also give it an default value false. Now, in your adapter function onBindViewHolder, you should set value of your checkbox ex.
card.checkBox.setChecked(locationCard.getIsChecked())
Also, in your onCheckedChanged you should update your data
locationCard.setIsChecked(isChecked)
Now each time your RecyclerView Adapter reuses and list item, it will set the value of its checkbox correctly. Hope this helps.

Related

Checkbox in RecyclerView index gets clicked twice

I have a RecyclerView list with CheckBox in the CardView, using a simple onClickListener. But when index 0 is clicked index 10 is also shown as clicked. The same if index 1 is clicked so is 11, index 2 so is 12, and so on. How do I solve this problem?
Three steps to solve it, and can be used everywhere you have a checkbox widget and it will be resued.
Firstly, Each adapter has a corresponding 'bean' binds to it. for example, List, The T is the bean.
Secondly, add a boolean field 'ischecked' into 'bean' class.
Finally, use this field to reset the status of checkbox when recycleview reuses checkbox, and update it when status of checkbox being changed.
RecyclerView will reuse the layouts from previous rows when scrolling, so if you check item 1, and scroll, item 11 will still be checked unless told to not be.
Within your onBindViewHolder, you want to set the layout to the current state of the object you're displaying.
For example, say we have a list of Dogs, and we can mark if we've pet the Dog.
class Dog {
public boolean hasPet = false;
public String name;
}
Now, if you're displaying each Dog, you can do.
void onBindViewHolder(MyViewHolder holde, int position) {
Dog dog = list[position];
holder.name = dog.name;
// Remove any onCheckChangeListener or else we'll change the previously rendered dog.
holder.check.setOnCheckedChangeListener(null);
// Set the checkbox to the current state of the dog.
holder.check.setChecked(dog.hasPet);
// Add a new onCheckChangeListener with the current dog.
holder.check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Logger.d("Clicked.");
dog.hasPet = isChecked;
}
});
}
This is because of the behavior of your RecyclerView. RecyclerView tries to recycle the views generated already with minimal changes in data. So in order to populate your data precisely in your list items, you need to tell exactly what it needs to show.
In your case, you need to keep the track of your checkbox click somewhere (maybe in a different array) so that you can populate the views accordingly. Let us consider the following code.
// Let us create an integer array having the same size of your list that is being passed to your RecyclerView
// Initially, all elements in the array is zero.
private int[] array = new int[yourList.size()];
Now in your onBindViewHolder, I think you have implemented the onClickListener for your CheckBox. Hence when you are clicking the CheckBox, set the corresponding element in your array to 1.
public void onClick(int position) {
// Checbox click action here
if (array[position] == 0)
array[position] = 1; // Use the position of your adapter to set the value.
else array[position] = 0; // Toggle the values on check/uncheck
}
Now in the onBindViewHolder while populating the CheckBox, check the value of its position in the array and set the checked status accordingly.
if(array[position] == 1) checkBox.setChecked(true);
else checkBox.setChecked(false);
Hope that helps!
The problem because you didn't keep the click state for each item. You can modify your pojo and adding a check state property or you can simply using SparseBooleanArray to hold the check state for all items.
Here the sample for using SparseBooleanArray.
Assuming we're using a simple pojo of User:
public class User {
private String id;
private String name;
// constructor, setter, getter
}
First, create a SparseBooleanArray to hold the selected flags like this:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> {
private List<User> mUsers;
private SparseBooleanArray mSelectedFlags;
public UserAdapter(List<User> users) {
mUsers = users;
mSelectedFlags = new SparseBooleanArray();
}
...
}
Second, save the state whenever you click the CheckBox in your ViewHolder:
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvName;
public TextView tvId;
public CheckBox cbxSelect;
public ViewHolder(View itemView) {
super(itemView);
...
// bind view here
cbxSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// set the state for specific item by its position.
mSelectedFlags.put(getAdapterPosition()), isChecked);
}
});
}
Last, set the state in onBindViewHolder:
#Override
public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
int itemPosition = viewHolder.getAdapterPosition();
User user = mUsers.get(itemPosition);
viewHolder.tvId.setText(user.getId());
viewHolder.tvName.setText(user.getName());
// set the check state for each item
// SparseBooleanArray will return false as default value
viewHolder.cbxSelect.setChecked(mFlagSelected.get(itemPosition));
}
The full adapter will be something like this:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> {
private List<User> mUsers;
private SparseBooleanArray mSelectedFlags;
public UserAdapter(List<User> users) {
mUsers = users;
mSelectedFlags = new SparseBooleanArray();
}
#Override
public UserAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
...
// inflate and return view holder.
return viewHolder;
}
#Override
public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
int itemPosition = viewHolder.getAdapterPosition();
User user = mUsers.get(itemPosition);
viewHolder.tvId.setText(user.getId());
viewHolder.tvName.setText(user.getName());
// set the check state for each item
// SparseBooleanArray will return false as default value
viewHolder.cbxSelect.setChecked(mFlagSelected.get(itemPosition));
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvName;
public TextView tvId;
public CheckBox cbxSelect;
public ViewHolder(View itemView) {
super(itemView);
...
// bind view here
cbxSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// set the state for specific item by its position.
mSelectedFlags.put(getAdapterPosition()), isChecked);
}
});
}
}

Working with Long Click Listener with recycler-android

i am working on a notapad like android app project. i which i have implemented recycler.
My project contains NotedAdaper class that extends RecyclerView.Adapter<NotesAdapter.ViewHolder>
in that class using the below code i used click listener,
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.ViewHolder> {
private List<Notes> mNotes;
private Context mContext;
public NotesAdapter(Context context, List<Notes> notes) {
mNotes = notes;
mContext = context;
}
#Override
public NotesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View notesView = inflater.inflate(R.layout.items_notes, parent, false);
// Return a new holder instance
ViewHolder viewHolder = new ViewHolder(notesView);
return viewHolder;
}
// Easy access to the context object in the recyclerview
private Context getContext() {
return mContext;
}
#Override
public void onBindViewHolder(NotesAdapter.ViewHolder viewHolder, final int position) {
// Get the data model based on position
Notes notes = mNotes.get(position);
// Set item views based on your views and data model
TextView textView = viewHolder.preTitle;
textView.setText(notes.getTitle());
TextView textView1 = viewHolder.preText;
textView1.setText(notes.getText());
String color=notes.getColor();
CardView preCard=viewHolder.preCard;
preCard.setBackgroundColor(Color.parseColor(color));
ImageView img = viewHolder.preImage;
img.setVisibility(View.GONE);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Notes notes = mNotes.get(position);
Intent intent = new Intent(view.getContext(),EditNote.class);
Bundle bundle = new Bundle();
bundle.putSerializable("DATA",notes);
intent.putExtras(bundle);
getContext().startActivity(intent);
Toast.makeText(getContext(), "Recycle Click" + position+" ", Toast.LENGTH_SHORT).show();
}
});
}
// Returns the total count of items in the list
#Override
public int getItemCount() {
return mNotes.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
// Your holder should contain a member variable
// for any view that will be set as you render a row
public RobotoTextView preTitle, preText;
public ImageView preImage;
public CardView preCard;
public ViewHolder(View itemView) {
super(itemView);
preTitle = (RobotoTextView) itemView.findViewById(R.id.preTitle);
preText = (RobotoTextView) itemView.findViewById(R.id.preText);
preImage=(ImageView) itemView.findViewById(R.id.preImage);
preCard=(CardView) itemView.findViewById(R.id.preCard);
}
}}
And its absolutely working find. on clicking of a item in recycler, it retrieves the data using position of that item. and showing in another activity.
just like, suppose a activity shows the list of notes created by user. and clicking on any note, it shows the full content of that note.
but now i want to implement Long click listener on the item. and get the position.
so that, i used the following code ...
viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
Notes notes = mNotes.get(position);
Toast.makeText(getContext(), "long Click" + position+" ", Toast.LENGTH_SHORT).show();
return false;
}
});
so, its also working.
but what i want is, on long click, it should only show that Toast.
but its not only showing the long click toast. but also recognising click listener and after showing the toast>> "Long click: ..." it executing the the code written for single click event.
n i dont want it.
both listeners should work separately.
but why its executing single click after long click??? any idea???
Am i making mistake anywhere?
So, the following changes in my code, help me to achieve my output.
1) The method onBindViewHolder is called every time when you bind your view with data. So there is not the best place to set click listener. You don't have to set OnClickListener many times for the one View. Thats why, i wrote click listeners in ViewHolder, (actually that was not my question, but i read somewhere that it would be the best practice, thats why i am following it)
like this,
public static class ViewHolder extends RecyclerView.ViewHolder {
// Your holder should contain a member variable
// for any view that will be set as you render a row
public ImageView preImage;
public CardView preCard;
// We also create a constructor that accepts the entire item row
// and does the view lookups to find each subview
public ViewHolder(final View itemView) {
// Stores the itemView in a public final member variable that can be used
// to access the context from any ViewHolder instance.
super(itemView);
itemView.findViewById(R.id.preTitle);
preImage=(ImageView) itemView.findViewById(R.id.preImage);
preCard=(CardView) itemView.findViewById(R.id.preCard);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
int p=getLayoutPosition();
System.out.println("LongClick: "+p);
return true;// returning true instead of false, works for me
}
});
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int p=getLayoutPosition();
Notes notes = mNotes.get(p);
Toast.makeText(getContext(), "Recycle Click" + p +" ", Toast.LENGTH_SHORT).show();
}
});
}
}
You may notice that, in onLongClick, i have returned "true", bydefault it was "false".
and this change works for me.
just make onLongClick(View v) returns return true instead of return false
this solved my problem it should solve yours too
i think you should set both the listeners from ViewHolder class.
itemView.setOnClickListener(...);
itemView.setOnLongClickListener(...);
And call getAdapterPosition() from ViewHolder to get the adapter position of the item.
You can checkout the following resource.
https://www.bignerdranch.com/blog/recyclerview-part-1-fundamentals-for-listview-experts/
I think this is an easier way to implement onClick and longClickListeners to RecyclerViews. Here's my code snippet. I've cut out unnecessary codes from here.
public class PrescriptionAdapter extends RecyclerView.Adapter<PrescriptionAdapter.ViewHolder> {
static final String TAG = "RecyclerViewAdapterMedicineFrequency";
ArrayList<Prescription> pdata;
Context context;
OnItemClickListener onItemClickListener;
OnItemLongClickListener onItemLongClickListener;
public PrescriptionAdapter(Context context, ArrayList<Prescription> presData, OnItemClickListener onItemClickListener, OnItemLongClickListener onItemLongClickListener) {
this.pdata = presData;
this.context = context;
this.onItemClickListener = onItemClickListener;
this.onItemLongClickListener = onItemLongClickListener;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView pName, totalMeds;
ImageView pImage;
OnItemClickListener onItemClickListener;
OnItemLongClickListener onItemLongClickListener;
public ViewHolder(View itemView, OnItemClickListener onItemClickListener, OnItemLongClickListener onItemLongClickListener) {
super(itemView);
pName = (TextView) itemView.findViewById(R.id.prescriptionName);
totalMeds = (TextView) itemView.findViewById(R.id.totalMeds);
pImage = (ImageView) itemView.findViewById(R.id.prescriptionImage);
this.onItemClickListener = onItemClickListener;
this.onItemLongClickListener = onItemLongClickListener;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(getAdapterPosition());
}
#Override
public boolean onLongClick(View v) {
onItemLongClickListener.onItemLongClick(getAdapterPosition());
return true;
}
}
public interface OnItemClickListener {
void onItemClick(int i);
}
public interface OnItemLongClickListener {
void onItemLongClick(int i);
}
}

RecyclerView checkbox deselect all?

I'm wondering how I'd be able to use a button in another class to deselect all checkboxes in my 3 recyclerviews(Tablayout, one recyclerview per tab). I have saved the checked value in shared pref as shown here:
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {
Context mContext;
ArrayList<Workout> workout;
SharedPreferences prefs;
int firstSecondOrThird;
int colorResId = R.color.defaultcard;
public MyRecyclerAdapter(Context context, ArrayList<Workout> workout, int thePosition) {
mContext = context;
this.workout = workout;
this.firstSecondOrThird = thePosition;
}
// INITIALIZE HOLDER
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.workout_item, null);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
//BIND DATA TO VIEWS
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
holder.exercise.setText(workout.get(position).getExercise());
holder.percent.setText(workout.get(position).getPercent());
holder.reps.setText(workout.get(position).getReps());
holder.weight.setText(workout.get(position).getWeight());
holder.check1.setOnCheckedChangeListener(null);
final Workout isCheck = workout.get(position);
prefs = mContext.getSharedPreferences("checkState", Context.MODE_PRIVATE);
holder.check1.setChecked(prefs.getBoolean(firstSecondOrThird+"checkState"+position, false));
isCheck.setCheck1(prefs.getBoolean(firstSecondOrThird+"checkState"+position, false));
holder.check1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
prefs.edit().putBoolean(firstSecondOrThird+"checkState"+position, isChecked).apply();
}
});
}
And here is where I try to clear shared pref, which I thought would also clear all checkmarks:
mButton = (Button) findViewById(R.id.button2);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
prefs.edit().clear();
prefs.edit().apply();
Toast.makeText(getApplicationContext(), "Checkboxes Cleared.", Toast.LENGTH_LONG).show();
}
});
}
Unfortunately, after clicking the button, all checkboxes that were previously selected are still selected. Thanks in advance!
EDIT: I tried to add an if statement to see if that would work, but now it doesn't load the saved checkmarks are all, even when the button isn't clicked... lol
prefs = mContext.getSharedPreferences("checkState", Context.MODE_PRIVATE);
String restoredCheck = prefs.getString("checkState", null);
if (restoredCheck != null) {
holder.check1.setChecked(prefs.getBoolean(firstSecondOrThird+"checkState"+position, false));
} else holder.check1.setChecked(false);
You need to alter the List inside the adapter, then, call ((MyRecyclerAdapter) mMyListView.getAdapter()).notifyDataSetChanged();
For experience, some times depending on what change are made, the adapter do not update with this, in this cases, i create a new adapter with the new list of data, and set to the ListView, after, you may need to call the notifyDataSetChanged() anyway
Edit:
Well, inside your adapter you use a `List', the state change must be done in that List, and after that you notify the adapter that the data was changed.
So you need a method to get the ArrayList and do something like:
mButton = (Button) findViewById(R.id.button2);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<Workout> list = ((MyRecyclerAdapter) MyListView.getAdapter()).getList();
for(Workout workout : list){
workout.setCheck(true);
}
((MyRecyclerAdapter) MyListView.getAdapter()).notifyDataSetChanged();
}
});
}
I'm not able to test right now, but i think it's some like that, like i said, if this don't work, create another adapter with the new data and set him to the ListView.
Ps. I considered you correctly check if the object isChecked and change the checkbox in the ViewHoler

Getting the checked states of a radio button in all the items in a recycler view

I have a RecyclerView which holds 10 views each having a CheckBox. Now, in my main activity when a menu button named "POST" is pressed I want to know whether all the CheckBox in each of the views of the RecyclerView is checked or not.
How can I implement this?
I advise you to pass additional variable isChecked inside every model of a list of models passed to RecyclerView.
Like that:
public class Model {
private boolean isChecked;
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
}
Then inside your RecyclerView ViewHolder, create a constructor:
public ListViewHolder(View view) {
super(view);
switchCompat = (SwitchCompat) view.findViewById(R.id.add_switch);
switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
getItemAt(getLayoutPosition()).setChecked(isChecked);
}
});
}
Then to get all button states just iterate through the list of models in Your activity:
public boolean areAllChecked() {
for (int i = 0; i < adapter.getItemCount(); i++) {
Model model = adapter.getItemAt(i);
if (!model .isChecked()) {
return false;
}
}
return true;
}
Add a boolean isChecked in your model class (Item which you are adding to RecyclerView Adapter)
In your adapter onBindViewHolder implement onCheckedChangeListener for your checkbox and set isChecked appropriately.
implement a isChecked(int position) method in your adapter. It should return checked value of the items specified by position
in your fragment/activity iterate through adapter items and find out if all items are checked or not.
Track the state of each checkbox in the adapter.
To do so let it have an map that stores a boolean value bound to a unique key for each checkbox. And also let it implement the OnCheckedChangeListener.
MyAdapter extends RecyclerView.Adapter implements OnCheckedChangeListener {
private Map<Object, Boolean> checkboxStates = new HasMap<>();
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checkboxStates.put(buttonView.getTag(), isChecked);
}
public Map<Object, Boolean> getCheckboxStates() {
//We don't want the caller to modify adapter state.
return Collections.unmodifiableMap(this.checkboxStates);
}
//other code
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
//your code
CheckBox cb;
//assuming that we have the reference to the cb view
//also assuming that cb has a unique identifiable tag assigned from the model
cb.setOnCheckedChangeListener(this);
if (this.checkboxStates.containsKey(cb.getTag()) {
cb.setChecked(this.checkboxStates.get(cb.getTag());
} else {
this.checkboxStates.put(cb.getTag(), cb.isChecked());
}
}
}
With this you can call the getCheckboxStates to get the states of each checkbox that was visible.
The key point here is that you need something unique identifiable for each item in the dataset that can be used as a tag for each checkbox that represents that item.

Dynamically add and hiding textViews

I've got "for each" loop that creates textView for every obiect from the list and add them to the linear layout. It works great. Then I want to hide all of the textViews when user clicks on toggle button but here I've got problem - only the last textView from the list is being hidden , rest of them is still visible. I tried to solve this problem with many solutions ( for example with getChild()), but nothing works.
final List<FilterItem> filterItemList = filterData.getFilterItemList();
for (FilterItem filterItem : filterItemList) {
final TextView filter = new TextView(MainPanelActivity.this);
filter.setText(filterItem.getFilterItemName());
filter.setTextColor(R.color.black);
linearLayout.addView(filter);
filter.setVisibility(View.GONE);
textLine.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
filter.setVisibility(View.VISIBLE);
} else {
filter.setVisibility(View.GONE);
}
}
});
Note that youre setting a listener for textLine inside the for loop - so for each iteration you set a new listener that changes the visibility of the TextView created in the current iteraton.
Move textLine.setOnCheckedChangeListener() outside of the for loop; and inside onCheckedChanged - loop through all children of linearLayout and set the visibility for each child.
textLine.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
for (View v : linearLayout.getChildren()) {
if (v instanceof TextView) {
if (isChecked) {
v.setVisibility(View.VISIBLE);
} else {
v.setVisibility(View.GONE);
}
}
}
You could keep a list of TextViews when you create them. Then set the click listener outside the for-loop as Dmitri says, which would iterate through the list of TextViews and set the visibility to GONE.
private void setup() {
List<View> textViews = new ArrayList<>();
for (FilterItem filterItem : filterData.getFilterItemList()) {
View view = createTextViewFor(filterItem);
linearLayout.addView(filter);
textViews.add(view);
}
updateVisibility(textViews, View.GONE);
textLine.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int visibility = isChecked ? View.VISIBLE : View.GONE;
updateVisibility(textViews, visibility);
}
}
);
}
private View createTextViewFor(FilterItem filterItem) {
TextView view = new TextView(MainPanelActivity.this);
view.setText(filterItem.getFilterItemName());
view.setTextColor(R.color.black);
view.addFilter(filterItem);
return view;
}
private void updateVisibility(List<View> views, int visibility) {
for (View view : views) {
view.setVisibility(visibility);
}
}
In case you want to display textView dynamically, I think putting textView inside RecyclerView will be a better idea. RecyclerView has its own Adapter which will make it easy to play with data and textViews. Give recyclerView a try. RecycerView for what you are trying to do can be learnt in few hours and sky is the limit for what you can do with recyclerView :)

Categories

Resources