How to prevent the duplication of `RecyclerView` when scrolling? - java

I am showing a love sign on my RecyclerView.
When user clicked the color of the love sign changes from default gray to red color but when I scrolled it is showing color in some other positions(not clicked). Also the clicked color changes to gray.
I found large number of solutions but nothing worked for me.
Please help.
I am giving you my codes
Featured Products class
public class FeaturedlistAdapter extends RecyclerView.Adapter<FeaturedlistAdapter.FeaturedView>
{
private Context context;
private List<Featured_data> featured_data;
public FeaturedlistAdapter(Context context, List<Featured_data> featured_data,MyAdapterListener myAdapterListener) {
this.context=context;
this.featured_data=featured_data;
this.onclickListener=myAdapterListener;
}
#NonNull
#Override
public FeaturedView onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate(R.layout.list_allbrands, viewGroup, false);
return new FeaturedView(view);
}
#Override
public void onBindViewHolder(#NonNull FeaturedView featuredView, int i) {
String price = featured_data.get(i).getProductPrice();
String name = featured_data.get(i).getProductName();
String quantity = featured_data.get(i).getProductQty();
featuredView.getTxt_brandname().setText(featured_data.get(i).getProductName());
String wishlist=featured_data.get(i).getWishlist();
Picasso.get().load(HomeConstants.BASE_URL + featured_data.get(i).getProductImage()).placeholder(R.drawable.whitebackground).into(featuredView.img_brand);
if (price != null && !price.equals("")) {
String total_price = price + " Rs";
featuredView.getTxt_brand_price().setText(total_price);
}
if (quantity != null && !quantity.equals("")) {
String total_quantity = quantity + " Items";
featuredView.getTxt_brand_item().setText(total_quantity);
}
if(wishlist!=null)
{
if(wishlist.equals("0"))
{
featuredView.img_wishlist.setColorFilter(Color.argb(255, 211, 211, 211));
featuredView.txt_count.setText("0");
}
else if(wishlist.equals("1"))
{
featuredView.img_wishlist.setColorFilter(Color.argb(255,255,0,0));
featuredView.txt_count.setText("1");
}
}
else
{
featuredView.img_wishlist.setColorFilter(Color.argb(255, 211, 211, 211));
featuredView.txt_count.setText("0");
}
}
#Override
public int getItemCount() {
return featured_data.size();
}
#Override
public long getItemId(int position) {
return super.getItemId(position);
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
class FeaturedView extends RecyclerView.ViewHolder {
ImageView img_brand,img_wishlist;
TextView txt_brandname,txt_brand_price,txt_brand_item,txt_count;
public ImageView getImg_brand() {
return img_brand;
}
public ImageView getImg_wishlist() {
return img_wishlist;
}
public TextView getTxt_brandname() {
return txt_brandname;
}
public TextView getTxt_brand_price() {
return txt_brand_price;
}
public TextView getTxt_brand_item() {
return txt_brand_item;
}
public TextView getTxt_count() {
return txt_count;
}
FeaturedView(#NonNull View itemView) {
super(itemView);
img_brand=itemView.findViewById(R.id.img_brand);
img_wishlist=itemView.findViewById(R.id.img_wishlist);
txt_brandname=itemView.findViewById(R.id.txt_brandname);
txt_brand_price=itemView.findViewById(R.id.txt_brand_price);
txt_brand_item=itemView.findViewById(R.id.txt_brand_item);
txt_count=itemView.findViewById(R.id.txt_count);
img_wishlist.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String value = txt_count.getText().toString();
if (value.equals("0")) {
img_wishlist.setColorFilter(Color.argb(255, 255, 0, 0));
txt_count.setText("1");
} else if (value.equals("1")) {
img_wishlist.setColorFilter(Color.argb(255, 211, 211, 211));
txt_count.setText("0");
}
onclickListener.wishlistOnclick(v,getAdapterPosition());
}
});
img_brand.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onclickListener.brandOnClick(v,getAdapterPosition());
}
});
}
}
private MyAdapterListener onclickListener;
public interface MyAdapterListener
{
void wishlistOnclick(View view ,int position);
void brandOnClick(View view,int position);
}
}

You need to keep the state of the view by using SparseBooleanArray. It is because in RecylerView the item will be shown with the previous view (if exist), i.e the view will be recycled first before used. Hence the mean of RecyclerView.
You can do something like this:
First, in your Adapter, add the SparseBooleanArray to hold the flags (Please read the comment in the code):
public class FeaturedlistAdapter extends RecyclerView.Adapter<FeaturedlistAdapter.FeaturedView>
{
private Context context;
private List<Featured_data> featuredData;
private SparseBooleanArray mSelectedFlags;
public FeaturedlistAdapter(Context context, List<Featured_data> featured_data,MyAdapterListener myAdapterListener) {
...
// init the flag
mSparseBooleanArray = new SparseBooleanArray();
}
#Override
public void onBindViewHolder(#NonNull FeaturedView featuredView, int i) {
int position = featuredView.getAdapterPosition();
Featured_data data = featuredData.get(position);
// reset the state of the view each time the
// view get recycled by applying the flag.
if(mSelectedFlags.get(position)) {
// set the selected state, i.e red
} else {
// SparseBooleanArray.get(i) is false if not found
// set the unselected state, i.e grey
}
}
then in your ViewHolder, set the state when member view is clicked/selected:
class FeaturedView extends RecyclerView.ViewHolder {
...
FeaturedView(#NonNull View itemView) {
...
img_wishlist.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
...
// save the selected state
mSparseBooleanArray.put(getAdapterPosition(), true);
}
...
}
}
Now the view selected/unselected state will be reset using the saved stated from your SparseBooleanArray flag holder.

Replace Following Code in your file and try
if(wishlist!=null)
{
if(wishlist.equals("1")) // change is here
{
featuredView.img_wishlist.setColorFilter(Color.argb((255,255,0,0));
featuredView.txt_count.setText("1");
}
else (wishlist.equals("0")) // change is here
{
featuredView.img_wishlist.setColorFilter(Color.argb(255,255,111,111));
featuredView.txt_count.setText("0");
}
}
else
{
featuredView.img_wishlist.setColorFilter(Color.argb(255, 211, 211, 211));
featuredView.txt_count.setText("0");
}
Also for this
img_wishlist.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
featured_data.get(getAdapterPosition).setWishlist(featured_data.get(getAdapterPosition).getWishlist().equals("0")?"1":"0");
notifyItemChanged(getAdapterPosition());
onclickListener.wishlistOnclick(v,getAdapterPosition());
}
});

public class FeaturedlistAdapter extends RecyclerView.Adapter<FeaturedlistAdapter.FeaturedView>
{
private Context context;
private List<Featured_data> featured_data;
private final SparseBooleanArray mSparseBooleanArray;
public FeaturedlistAdapter(Context context, List<Featured_data> featured_data,MyAdapterListener myAdapterListener) {
this.context=context;
this.featured_data=featured_data;
this.onclickListener=myAdapterListener;
// init the flag
mSparseBooleanArray = new SparseBooleanArray();
}
#NonNull
#Override
public FeaturedView onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate(R.layout.list_allbrands, viewGroup, false);
return new FeaturedView(view);
}
#Override
public void onBindViewHolder(#NonNull FeaturedView featuredView, int i) {
String price = featured_data.get(i).getProductPrice();
String name = featured_data.get(i).getProductName();
String quantity = featured_data.get(i).getProductQty();
featuredView.getTxt_brandname().setText(featured_data.get(i).getProductName());
String wishlist=featured_data.get(i).getWishlist();
Picasso.get().load(HomeConstants.BASE_URL + featured_data.get(i).getProductImage()).placeholder(R.drawable.whitebackground).into(featuredView.img_brand);
if (price != null && !price.equals("")) {
String total_price = price + " Rs";
featuredView.getTxt_brand_price().setText(total_price);
}
if (quantity != null && !quantity.equals("")) {
String total_quantity = quantity + " Items";
featuredView.getTxt_brand_item().setText(total_quantity);
}
if(wishlist!=null)
{
if(wishlist.equals("0"))
{
featuredView.img_wishlist.setColorFilter(Color.argb(255, 211, 211, 211));
featuredView.txt_count.setText("0");
}
else if(wishlist.equals("1"))
{
featuredView.img_wishlist.setColorFilter(Color.argb(255,255,0,0));
featuredView.txt_count.setText("1");
}
}
int position=featuredView.getAdapterPosition();
if(mSparseBooleanArray.get(position))
{
String value = featuredView.txt_count.getText().toString();
if (value.equals("0")) {
featuredView.img_wishlist.setColorFilter(Color.argb(255, 255, 0, 0));
// save the selected state
}
else if (value.equals("1")) {
featuredView.img_wishlist.setColorFilter(Color.argb(255,211,211,211));
// save the selected state
}
}
}
#Override
public int getItemCount() {
return featured_data.size();
}
#Override
public long getItemId(int position) {
return super.getItemId(position);
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
class FeaturedView extends RecyclerView.ViewHolder {
ImageView img_brand,img_wishlist;
TextView txt_brandname,txt_brand_price,txt_brand_item,txt_count;
public ImageView getImg_brand() {
return img_brand;
}
public ImageView getImg_wishlist() {
return img_wishlist;
}
public TextView getTxt_brandname() {
return txt_brandname;
}
public TextView getTxt_brand_price() {
return txt_brand_price;
}
public TextView getTxt_brand_item() {
return txt_brand_item;
}
public TextView getTxt_count() {
return txt_count;
}
FeaturedView(#NonNull View itemView) {
super(itemView);
img_brand=itemView.findViewById(R.id.img_brand);
img_wishlist=itemView.findViewById(R.id.img_wishlist);
txt_brandname=itemView.findViewById(R.id.txt_brandname);
txt_brand_price=itemView.findViewById(R.id.txt_brand_price);
txt_brand_item=itemView.findViewById(R.id.txt_brand_item);
txt_count=itemView.findViewById(R.id.txt_count);
img_wishlist.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String value = txt_count.getText().toString();
if (value.equals("0")) {
img_wishlist.setColorFilter(Color.argb(255, 255, 0, 0));
txt_count.setText("1");
} else if (value.equals("1")) {
img_wishlist.setColorFilter(Color.argb(255,211,211,211));
txt_count.setText("0");
}
onclickListener.wishlistOnclick(v,getAdapterPosition());
mSparseBooleanArray.put(getAdapterPosition(), true);
notifyDataSetChanged();
}
});
img_brand.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onclickListener.brandOnClick(v,getAdapterPosition());
}
});
}
}
private MyAdapterListener onclickListener;
public interface MyAdapterListener
{
void wishlistOnclick(View view ,int position);
void brandOnClick(View view,int position);
}
}

Related

How to manage multiple positions in RecyclerView OnClickListener

I want to know how I can get access to other elements of the array in this onclicklistener for a Recycler view. Specifically, I want to be able to change the enabled state of a position other than the current Listener position, but within the click event.
I'm trying to make it such that if three colors are checked (those are check boxes) every box not checked will be disabled until the number of boxes checked is < 3.
The for-loops I have I wrote make sense, but I can't programmatically change the enabled state within the onClickListener for some reason.
private void buildRecyclerView() {
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mAdapter = new ExampleAdapter(mExampleList);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new ExampleAdapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
boolean checkedState;
if (mExampleList.get(position).getChecked1() == false) {
checkedState = true;
} else {
checkedState = false;
}
changeItem(position, checkedState);
int sum = 0;
for (int i = 0; i < stringArray.length; i++) {
Boolean checked = mExampleList.get(i).getChecked1();
if (checked == true) {
sum = sum + 1;
}
}
for (int i = 0; i < stringArray.length; i++) {
Boolean checked = mExampleList.get(i).getChecked1();
if (!checked && sum == 3) {
mExampleList.get(i).setEnabled1(false);
} else {
mExampleList.get(i).setEnabled1(true);
}
}
}
});
}
adapter
public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder> {
private ArrayList<ExampleItem> mExampleList;
private OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public static class ExampleViewHolder extends RecyclerView.ViewHolder {
public CheckBox mCheckBox;
public ExampleViewHolder(#NonNull View itemView, final OnItemClickListener listener) {
super(itemView);
mCheckBox = itemView.findViewById(R.id.checkBox);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null){
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION);
listener.onItemClick(position);
}
}
});
}
}
public ExampleAdapter(ArrayList<ExampleItem> exampleList) {
mExampleList = exampleList;
}
#NonNull
#Override
public ExampleViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.example_item, parent, false);
ExampleViewHolder evh = new ExampleViewHolder(v, mListener);
return evh;
}
#Override
public void onBindViewHolder(#NonNull ExampleViewHolder holder, int position) {
ExampleItem currentItem = mExampleList.get(position);
holder.mCheckBox.setText(currentItem.getCheckText());
holder.mCheckBox.setEnabled(currentItem.getEnabled1());
holder.mCheckBox.setChecked(currentItem.getChecked1());
}
#Override
public int getItemCount() {
return mExampleList.size();
}
}
Item Class
public class ExampleItem {
public String mCheckText;
public Boolean mEnabled;
public Boolean mChecked;
public ExampleItem(String mCheckText, Boolean mEnabled, Boolean mChecked) {
this.mCheckText = mCheckText;
this.mEnabled = mEnabled;
this.mChecked = mChecked;
}
public ExampleItem(String mCheckText) {
this.mCheckText = mCheckText;
}
public String getCheckText() {
return mCheckText;
}
public void setCheckText(String mCheckText) {
this.mCheckText = mCheckText;
}
public Boolean getEnabled1() {
return mEnabled;
}
public void setEnabled1(Boolean mEnabled) {
this.mEnabled = mEnabled;
}
public Boolean getChecked1() {
return mChecked;
}
public void setChecked1(Boolean mChecked) {
this.mChecked = mChecked;
}
}
In other words, I am trying to make everything below blue disabled until I uncheck Red, Green, or Blue!
Try the following:
In adapter, add below codes:
private int selectedCount = 0;
public int getSelectedCount() {
return selectedCount;
}
public void setSelectedCount(int selectedCount) {
this.selectedCount = selectedCount;
notifyDataSetChanged();
}
and change onBindViewHolder() to:
#Override
public void onBindViewHolder(#NonNull ExampleViewHolder holder, int position) {
ExampleItem currentItem = mExampleList.get(position);
holder.mCheckBox.setText(currentItem.getCheckText());
holder.mCheckBox.setChecked(currentItem.getChecked1());
if ((selectedCount == 3)) holder.mCheckBox.setEnabled(currentItem.getChecked1());
else holder.mCheckBox.setEnabled(true);
}
Then in Activity/Fragment, change mAdapter.setOnItemClickListener(new ExampleAdapter.OnItemClickListener()... to:
mAdapter.setOnItemClickListener(new ExampleAdapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
boolean checkedState;
int selectedCount = mAdapter.getSelectedCount();
if ((selectedCount != 3) || (mExampleList.get(position).getChecked1())) {
if (mExampleList.get(position).getChecked1() == false) {
checkedState = true;
selectedCount++;
} else {
checkedState = false;
selectedCount--;
}
changeItem(position, checkedState);
mAdapter.setSelectedCount(selectedCount);
}
}
});
Pls note that no need to have mEnabled field in the ExampleItem class. Hope that helps!
Explanantion:
About the onClick:- This is because CheckBox totally covered the layout, so itemView cannot recieve the click event. About RecyclerView:- The idea is simple, after modified the data set [not list, here I refer to the mExampleList and also the selectedCount], then call notifyDataSetChanged() which will redraw all recycler item views.
You would need to create a setter function for your 'mExampleList' in your Adpater class, to update the dataset that the adapter is using. It obviously does not change anything, if you make changes to 'mExampleList' in your activity, without updating the list used by the Adapter.
So at the end of your click listener you would have something like that:
mAdapter.setExampleList(mExampleList)
mAdapter.notifyDataSetChanged()

STRIKE_THRU_TEXT_FLAG not working as Expected

This is my RecyclerView Adaptor Class
public class TodoAdaptor extends RecyclerView.Adapter<TodoAdaptor.SingleTodoView> {
private CheckBox checkbox;
private TextView title, dueDate;
private Context context;
private ArrayList<SingleTodo> todoList;
private onItemCLickListener itemCLickListener;
public TodoAdaptor(Context context, ArrayList<SingleTodo> todoList, onItemCLickListener onItemClickListener) {
this.context = context;
this.todoList = todoList;
this.itemCLickListener = onItemClickListener;
}
#NonNull
#Override
public SingleTodoView onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_todo, parent, false);
return new SingleTodoView(v, itemCLickListener);
}
#Override
public void onBindViewHolder(#NonNull SingleTodoView holder, int position) {
SingleTodo singleTodo = todoList.get(position);
checkbox.setChecked(singleTodo.isComplete());
title.setText(singleTodo.getTitle());
if (singleTodo.isComplete()) {
title.setPaintFlags(title.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
Toast.makeText(context, "IsCompleted", Toast.LENGTH_SHORT).show();
} else {
title.setPaintFlags(title.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
Toast.makeText(context, "Not IsCompleted", Toast.LENGTH_SHORT).show();
}
if (singleTodo.getDueDate().isEmpty()) {
dueDate.setVisibility(View.GONE);
} else {
dueDate.setText(singleTodo.getDueDate());
}
}
#Override
public int getItemCount() {
return todoList.size();
}
class SingleTodoView extends RecyclerView.ViewHolder {
private SingleTodoView(#NonNull View itemView, final onItemCLickListener itemCLickListener) {
super(itemView);
checkbox = itemView.findViewById(R.id.todo_list_completed_checkbox);
title = itemView.findViewById(R.id.todo_list_title);
dueDate = itemView.findViewById(R.id.todo_list_due_date);
title.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemCLickListener.onTextClickListener(getAdapterPosition());
}
});
checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemCLickListener.onCheckboxClickListener(getAdapterPosition());
}
});
}
}
public interface onItemCLickListener {
void onTextClickListener(int position);
void onCheckboxClickListener(int position);
}
}
This is My Adaptor
todoAdaptor = new TodoAdaptor(this, singleTodoArrayList, new TodoAdaptor.onItemCLickListener() {
#Override
public void onTextClickListener(int position) {
singleTodo = singleTodoArrayList.get(position);
singleTodo.setTitle("This is Test");
singleTodoArrayList.set(position, singleTodo);
todoAdaptor.notifyItemChanged(position);
}
#Override
public void onCheckboxClickListener(int position) {
singleTodo = singleTodoArrayList.get(position);
singleTodo.setComplete(!singleTodo.isComplete());
singleTodoArrayList.set(position, singleTodo);
todoAdaptor.notifyItemChanged(position);
}
});
and This is my SingleTodo Class
package com.example.simpletodo.classes;
public class SingleTodo {
private int id;
private String title;
private String dueDate;
private boolean isComplete;
public SingleTodo(int id, String title, String dueDate, boolean isComplete) {
this.id = id;
this.title = title;
this.dueDate = dueDate;
this.isComplete = isComplete;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getDueDate() {
return dueDate;
}
public boolean isComplete() {
return isComplete;
}
public void setId(int id) {
this.id = id;
}
public void setTitle(String title) {
this.title = title;
}
public void setDueDate(String dueDate) {
this.dueDate = dueDate;
}
public void setComplete(boolean complete) {
isComplete = complete;
}
}
Whenever I check the checkbox, Text of that item should paint Strikethrough and Its not working as Expected
I have 3 Items in the list, when i click checkbox Item get Checked and Text Strikethrough works but when i again click checkbox checkbox stay checked (although Object is being Updated as it should be) and strikethrought text revert to normal, and i have to click checkbox twice again for check box to get unchecked
other issue is that when i checked on item and then i try to check other item, Current Item text get replaced by one of the other checked item Text.
Images :
Default:
When i click the Checkbox Once:
When i Click the Checkbox Again:
When i Checked multiple Items one by one(I have not changed position of any item before checking they was in default order and after checking --in order-- this is what i get)
Any Help is Appreciated. I just want my code to work as Expected.
I found the Solution from this Question
I had to change my Adaptor Class. I Declared Views inside my view holder class and onBindViewHolder, i am using first parameter (holder) to get my Views
public class TodoAdaptor extends RecyclerView.Adapter<TodoAdaptor.SingleTodoView> {
private boolean darkTheme;
private Context context;
private ArrayList<SingleTodo> todoList;
private onItemCLickListener itemCLickListener;
public TodoAdaptor(Context context, ArrayList<SingleTodo> todoList, boolean darkTheme, onItemCLickListener onItemClickListener) {
this.darkTheme = darkTheme;
this.context = context;
this.todoList = todoList;
this.itemCLickListener = onItemClickListener;
}
#NonNull
#Override
public SingleTodoView onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.single_todo, parent, false);
return new SingleTodoView(v, itemCLickListener);
}
#Override
public void onBindViewHolder(#NonNull SingleTodoView holder, int position) {
SingleTodo singleTodo = todoList.get(position);
holder.checkbox.setChecked(singleTodo.isComplete());
holder.title.setText(singleTodo.getTitle());
if (singleTodo.isComplete()) {
holder.title.setPaintFlags(holder.title.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
holder.title.setPaintFlags(holder.title.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
if (singleTodo.getDueDate().isEmpty()) {
holder.dueDate.setVisibility(View.GONE);
} else {
holder.dueDate.setVisibility(View.VISIBLE);
holder.dueDate.setText(singleTodo.getDueDate());
}
}
#Override
public int getItemCount() {
return todoList.size();
}
class SingleTodoView extends RecyclerView.ViewHolder {
private CheckBox checkbox;
private TextView title, dueDate;
private SingleTodoView(#NonNull View itemView, final onItemCLickListener itemCLickListener) {
super(itemView);
checkbox = itemView.findViewById(R.id.todo_list_completed_checkbox);
title = itemView.findViewById(R.id.todo_list_title);
dueDate = itemView.findViewById(R.id.todo_list_due_date);
if (darkTheme) {
title.setTextColor(context.getResources().getColor(R.color.colorLightGray));
dueDate.setTextColor(context.getResources().getColor(R.color.colorLightGray));
} else {
title.setTextColor(context.getResources().getColor(R.color.colorBlack));
dueDate.setTextColor(context.getResources().getColor(R.color.colorBlack));
}
title.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemCLickListener.onTextClickListener(getAdapterPosition());
}
});
checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemCLickListener.onCheckboxClickListener(getAdapterPosition());
}
});
}
}
public interface onItemCLickListener {
void onTextClickListener(int position);
void onCheckboxClickListener(int position);
}
}

Checkbox refreshing in false when I use notifyDataSetChanged();

My problem is the one wrote on the title, I have a recyclerview with checkboxes and radiobuttons before I started to use the notifyDataSetChanged() (because I need to update the recyclerview) the checkboxes and radiobuttons were been checked, but now the checks don't work. (I think that it work but it becomes false instantly)
I am sure of this because if I comment the line of notifyDataSetChanged() then it still working as well.
Do you guys know how to fix it?
Java for the adapter Class:
public class OptionModesAdapter extends RecyclerView.Adapter<OptionModesAdapter.ViewHolder> {
private int fatherMode;
private int fatherId;
private Context context;
private AsyncAdapters asyncAdapters;
private ArrayList<Modes> modes;
private ArrayList<Modes> selected;
private ArrayList<IUrbanRadioButton> radiosSelected;
OptionModesAdapter(ArrayList<Modes> modes, Context context, int fatherMode, AsyncAdapters asyncAdapters) {
this.modes = modes;
this.context = context;
this.fatherMode = fatherMode;
this.selected = new ArrayList<>();
this.asyncAdapters = asyncAdapters;
this.radiosSelected = new ArrayList<>();
}
class ViewHolder extends RecyclerView.ViewHolder {
private CheckBox cbOptionMode;
private IUrbanRadioButton rbOptionMode;
ViewHolder(View itemView) {
super(itemView);
cbOptionMode = itemView.findViewById(R.id.cb_option_mode);
rbOptionMode = itemView.findViewById(R.id.rb_option_mode);
}
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View myView = LayoutInflater.from(parent.getContext()).inflate(R.layout.option_modes, parent, false);
return new OptionModesAdapter.ViewHolder(myView);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
switch (fatherMode) {
case 0:
holder.rbOptionMode.setVisibility(View.VISIBLE);
holder.cbOptionMode.setVisibility(View.GONE);
holder.rbOptionMode.setText(modes.get(position).getTranslationName(context));
holder.rbOptionMode.setParentName(String.valueOf(modes.get(position).getIdFather()));
onClickRadioButton(holder.rbOptionMode, position);
break;
case 1:
holder.cbOptionMode.setVisibility(View.VISIBLE);
holder.rbOptionMode.setVisibility(View.GONE);
holder.cbOptionMode.setText(modes.get(position).getTranslationName(context));
onClickCheckBox(holder.cbOptionMode, position);
break;
default:
Log.e(CustomConstants.EXCEPTION, "OptionModesAdapter: ln 72. Esto no es un modo admitido");
break;
}
}
private void onClickCheckBox(final CheckBox checkBox, final int position) {
checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (selectedContainsCB(checkBox)) {
removeOldCb(checkBox);
} else {
addNewCb(checkBox);
}
fatherId = modes.get(position).getIdFather();
asyncAdapters.onInnerClicked(selected, false, fatherId);
}
});
}
private boolean selectedContainsCB(CheckBox checkBox) {
Modes newMode = findModeByCheckBox(checkBox);
return selected.contains(newMode);
}
private Modes findModeByCheckBox(CheckBox checkBox) {
Modes modeToReturn = new Modes();
for (Modes currentMode : modes) {
if (currentMode.getTranslationName(context).equals(checkBox.getText().toString())) {
modeToReturn = currentMode;
break;
}
}
return modeToReturn;
}
private void removeOldCb(CheckBox checkBox) {
Modes modeToRemove = findModeByCheckBox(checkBox);
checkBox.setChecked(false);
selected.remove(modeToRemove);
}
private void addNewCb(CheckBox checkBox) {
Modes modeToAdd = findModeByCheckBox(checkBox);
checkBox.setChecked(true);
selected.add(modeToAdd);
}
private void onClickRadioButton(final IUrbanRadioButton iUrbanRadioButton, final int position) {
iUrbanRadioButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
settingFalseAllRadios();
deletingAllModesRadios();
addNewRb(iUrbanRadioButton);
radiosSelected.add(iUrbanRadioButton);
iUrbanRadioButton.setChecked(true);
fatherId = modes.get(position).getIdFather();
asyncAdapters.onInnerClicked(selected, true, fatherId);
}
});
}
private void settingFalseAllRadios() {
for (IUrbanRadioButton iUrbanRadioButton : radiosSelected) {
iUrbanRadioButton.setChecked(false);
}
radiosSelected.clear();
}
private void deletingAllModesRadios() {
selected.clear();
}
private Modes findModeByRadioButton(IUrbanRadioButton iUrbanRadioButton) {
Modes modeToReturn = new Modes();
for (Modes currentMode : modes) {
if (currentMode.getTranslationName(context).equals(iUrbanRadioButton.getText().toString())) {
modeToReturn = currentMode;
break;
}
}
return modeToReturn;
}
private void addNewRb(IUrbanRadioButton iUrbanRadioButton) {
Modes modeToAdd = findModeByRadioButton(iUrbanRadioButton);
selected.add(modeToAdd);
}
#Override
public int getItemCount() {
return modes.size();
}
}
Thank you in advance.
Ok guys, I just to solve that, I was calling notifyDataSetChanged() from the class which contain the Adapter. This is because the recyclerView were refreshing all the times and the checkboxes and radiobuttons don't be printed as checked.
The solution that works to me is calling the notifyDataSetChanged() inside the recyclerView. Just like this:
checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//My code...
notifyDataSetChanged();
}
});

Multi selection in RecyclerView?

Hello I am trying to implement multi select in recycler view android for showing an icon when clicked on that particular view, I have tried the below code and is working fine for that particular position, however there are other several views that too are getting updated, so please check and let me know what am I missing
Here is my adapter code:
public class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
Context context;
ArrayList<String> alContactName, alContactEmail, alContactNumber;
ArrayList<Boolean> alFromLinkedIn;
int mergeFlag=0;
private static SparseBooleanArray selectedItems;
ArrayList<Integer> alSelectedPositions;
public ContactsAdapter(Context context, ArrayList<String> alContactName, ArrayList<String> alContactEmail, ArrayList<String> alContactNumber, ArrayList<Boolean> alisFromLinkedIn) {
//Include one more variable for checking type i.e linked in or normal contact
super();
this.context = context;
this.alContactName = alContactName;
this.alContactEmail = alContactEmail;
this.alContactNumber = alContactNumber;
this.alFromLinkedIn = alisFromLinkedIn;
alSelectedPositions=new ArrayList<>();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_merge_contact, parent, false);
return new ContactsHolder(view);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
try {
((ContactsHolder) holder).relMain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
alSelectedPositions.add(position);
notifyDataSetChanged();
}
});
if(alSelectedPositions.get(position)==position){
((ContactsHolder) holder).imgMerge.setVisibility(View.VISIBLE);
}
else {
((ContactsHolder) holder).imgMerge.setVisibility(View.GONE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
check updated code. I have modified the #tahsinRupam code.
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
try {
((ContactsHolder) holder).relMain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(alSelectedPositions.size>0)
{
for(int i=0;i<a1SelectedPositions.size;i++)
{
//if you want to cleasr previous details of array
if(a1SelectedPositions.contains(position))
alSelectedPositions.remove(position);
else
alSelectedPositions.add(position);
}
}
else
{
alSelectedPositions.add(position);
notifyDataSetChanged();
}
});
//update the position on scroll
for(int i=0;i<a1SelectedPositions.size;i++)
{
if(alSelectedPositions.get(i)==position){
((ContactsHolder)holder).imgMerge.setVisibility(View.VISIBLE);
}
else {
((ContactsHolder) holder).imgMerge.setVisibility(View.GONE);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Recently I had to implement a multi select RecyclerView, below I attached a simplified code snippet for a clean way to implement multi-select feature in RecyclerView:
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemHolder> implements IMultiSelectableList<Item> {
boolean selectionMode = false;
HashSet<Item> selectedItems;
ArrayList<Item> mItems;
public ItemAdapter(ArrayList<Item> Items) {
super();
selectedItems = new HashSet<>();
mItems = Items;
}
public void enterSelectionModeWithItem(int selectedItemPosition){
if(selectedItemPosition >= 0 && selectedItemPosition < mItems.size())
selectedItems.add(mItems.get(selectedItemPosition));
selectionMode = true;
notifyDataSetChanged();
}
public void clearSelectionMode() {
selectionMode = false;
selectedItems.clear();
notifyDataSetChanged();
}
public class ItemHolder extends RecyclerView.ViewHolder{
ImageView mImage;
public ItemHolder(View itemView) {
super(itemView);
mImage = itemView.findViewById(R.id.image);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
if(!selectionMode){
int selectedPosition = getAdapterPosition();
Item selectedItem = mItems.get(selectedPosition);
enterSelectionModeWithItem(selectedItem);
return true;
}
return false;
}
});
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int selectedPosition = getAdapterPosition();
Item selectedItem = mItems.get(selectedPosition);
//Capture Clicks in Selection Mode
if(selectionMode){
if(selectedItems.contains(selectedItem)){
selectedItems.remove(selectedItem);
mImage.setImageResource(R.drawable.ic_checkbox_blank_circle_outline_grey600_48dp);
} else {
selectedItems.add(selectedItem);
mImage.setImageResource(R.drawable.ic_checkbox_marked_circle_grey600_48dp);
}
}
}
});
}
public void setupView(Item item){
if(selectionMode){
if(selectedItems.contains(item)){
mImage.setImageResource(R.drawable.ic_checkbox_marked_circle_grey600_48dp);
} else {
mImage.setImageResource(R.drawable.ic_checkbox_blank_circle_outline_grey600_48dp);
}
}
}
#Override
public ItemAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_item, parent, false);
return new ItemHolder(view);
}
#Override
public void onBindViewHolder(ItemAdapter.ItemHolder holder, int position) {
holder.setupView(mItems.get(position));
}
#Override
public int getItemCount() {
return mItems != null ? mItems.size() : 0;
}
}
, I use an image to show selection like Gmail app but feel free to use whatever works for you (background color, font style, etc).
P.S: I designed a callback interface for a simple selection interactions, if it helps I can attach it too! Cheers!
You've to do some specific things:
Initialize an int type array (type can be different) and assign 0 value to all it's elements.
int[] selectedPos = null;
public ContactsAdapter(Context context, ArrayList<String> alContactName, ArrayList<String> alContactEmail, ArrayList<String> alContactNumber, ArrayList<Boolean> alisFromLinkedIn) {
//Include one more variable for checking type i.e linked in or normal contact
super();
this.context = context;
this.alContactName = alContactName;
this.alContactEmail = alContactEmail;
this.alContactNumber = alContactNumber;
this.alFromLinkedIn = alisFromLinkedIn;
alSelectedPositions=new ArrayList<>();
for(int i = 0 ; i < alContactName.size() ; i++)
selectedPos[i] = 0;
}
Store the selected positions in selectedPos.
Then, check if the position is selected and set visibility accordingly:
In onBindViewHolder() add the following code:
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
try {
((ContactsHolder) holder).relMain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selectedPos[position] = 1;
notifyDataSetChanged();
}
});
} catch (Exception e) {
e.printStackTrace();
}
// Checking if the position was selected
if(selectedPos[position] == 1)
((ContactsHolder) holder).imgMerge.setVisibility(View.VISIBLE);
else
((ContactsHolder) holder).imgMerge.setVisibility(View.GONE);
}
I have resolved my issue here is the code if it could help someone:
#Override
public ContactsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_merge_contact, parent, false);
final ContactsHolder holder = new ContactsHolder(view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (holder.getAdapterPosition() != RecyclerView.NO_POSITION) {
mSelectedItemPosition = holder.getAdapterPosition();
//notifyItemChanged(holder.getAdapterPosition());
notifyDataSetChanged();
}
}
});
return holder;
}
#Override
public void onBindViewHolder(ContactsHolder holder, int position) {
try {
if (mSelectedItemPosition == position) {
if (mergeFlag != 1) {
holder.imgMerge.setVisibility(View.VISIBLE);
mergeFlag = 1;
selectdParentId = contactsModels.get(position).alContactIdList;
} else{
//holder.relDone.setVisibility(View.GONE);
if (!selectdParentId.equals(contactsModels.get(position).alContactIdList)) {
holder.relDone.setVisibility(View.VISIBLE);
alChildId.add(contactsModels.get(position).alContactIdList);
} else {
holder.imgMerge.setVisibility(View.VISIBLE);
}
}
} else {
holder.imgMerge.setVisibility(View.GONE);
holder.relDone.setVisibility(View.GONE);
}
}

Android Adapter doesn't work when selecting multiple cardviews

I have a problem, I don't understand why my CardViews have this effect.
I need select one or more CardViews but my adapter does not work fine. Is my implementation of the adapter incorrect?
My Adapter
public class PersonasAdapter extends RecyclerView.Adapter < PersonasAdapter.PersonasViewHolder > {
private Persona subject;
private List < Persona > personastList;
public PersonasAdapter() {}
public PersonasAdapter(List < Persona > personastList) {
this.personastList = personastList;
}
#Override
public void onBindViewHolder(final PersonasViewHolder personasViewHolder, int i) {
Persona ci = personastList.get(i);
personasViewHolder.txtNombre.setText(ci.getNombre());
personasViewHolder.txtUsuario.setText(ci.getUsuario());
personasViewHolder.txtTwitter.setText(ci.getTwitter());
subject = personastList.get(i);
personasViewHolder.card_view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Toast.makeText(v.getContext(), "Eliminar Cardview", Toast.LENGTH_SHORT).show();
personasViewHolder.card_view.setBackgroundResource(R.color.colorPrimary);
return false;
}
});
personasViewHolder.card_view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Reproducir", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public PersonasViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_layout_persona, viewGroup, false);
cardView
return new PersonasViewHolder(itemView);
}
Class Static
public static class PersonasViewHolder extends RecyclerView.ViewHolder {
protected TextView txtNombre;
protected TextView txtUsuario;
protected TextView txtTwitter;
protected CardView card_view;
public PersonasViewHolder(View v) {
super(v);
txtNombre = (TextView) v.findViewById(R.id.txtNombre);
txtUsuario = (TextView) v.findViewById(R.id.txtUsuario);
txtTwitter = (TextView) v.findViewById(R.id.txtTwitter);
card_view = (CardView) v.findViewById(R.id.card_view);
}
}
//Metodo que nos retornarta la cantidad de personas en la lista
#Override
public int getItemCount() {
return personastList.size();
}
}
The problem is the following:
You perfom a Long Click on the first PersonasViewHolder of your list.
Then, in your onLongClickListener, you change the background color of that holder.
But that holder is then re-used for later positions in the recycler-view, giving the sensation that the background is being repeated in later elements.
You can fix it by storing the state of each cardview in an array, and then binding the correct color for each position. I modified your code to show this idea:
public class PersonasAdapter extends RecyclerView.Adapter < PersonasAdapter.PersonasViewHolder > {
private Persona subject;
private List < Persona > personastList;
private boolean[] selectedPersonas;
public PersonasAdapter() {}
public PersonasAdapter(List < Persona > personastList) {
this.personastList = personastList;
this.selectedPersonas = new boolean[personasList.size()];
for (int i = 0; i < personasList.size(); i++) {
this.selectedPersonas[i] = false;
}
}
#Override
public void onBindViewHolder(final PersonasViewHolder personasViewHolder, final int i) {
Persona ci = personastList.get(i);
personasViewHolder.txtNombre.setText(ci.getNombre());
personasViewHolder.txtUsuario.setText(ci.getUsuario());
personasViewHolder.txtTwitter.setText(ci.getTwitter());
subject = personastList.get(i);
updatePersonaHolderBackground(personaViewHolder, i);
personasViewHolder.card_view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Toast.makeText(v.getContext(), "Eliminar Cardview", Toast.LENGTH_SHORT).show();
selectedPersonas[i] = !selectedPersonas[i];
updatePersonaHolderBackground(personaViewHolder, i);
return false;
}
});
personasViewHolder.card_view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Reproducir", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public PersonasViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_layout_persona, viewGroup, false);
cardView
return new PersonasViewHolder(itemView);
}
private void updatePersonaHolderBackground(final PersonasViewHolder personasViewHolder, final int i) {
if (selectedPersonas[i]) {
personasViewHolder.card_view.setBackgroundResource(R.color.colorPrimary);
} else {
// TODO: change the color of personasViewHolder back to normal using whatever color you want.
}
}
I solved my problem.
The problem are the position the cardview.
i declare global variable
int globalPosition;
and
personasViewHolder.card_view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Toast.makeText(v.getContext(), "Eliminar Cardview", Toast.LENGTH_SHORT).show();
personasViewHolder.card_view.setBackgroundResource(R.color.colorPrimary);
globalPosition=i;
notifyDataSetChanged();
return false;
}
});
and a validation in
and a if in onBindViewHolder
if (i == globalPosition) {
personasViewHolder.card_view.setBackgroundResource(R.color.colorPrimary);
} else {
personasViewHolder.card_view.setBackgroundResource(R.color.colorAccent);
}
and the result it's this.
public class PersonasAdapter extends RecyclerView.Adapter < PersonasAdapter.PersonasViewHolder > {
private Persona subject;
private List < Persona > personastList;
public PersonasAdapter() {}
int globalPosition;
public PersonasAdapter(List < Persona > personastList) {
this.personastList = personastList;
}
#Override
public void onBindViewHolder(final PersonasViewHolder personasViewHolder, final int i) {
Persona ci = personastList.get(i);
personasViewHolder.txtNombre.setText(ci.getNombre());
personasViewHolder.txtUsuario.setText(ci.getUsuario());
personasViewHolder.txtTwitter.setText(ci.getTwitter());
subject = personastList.get(i);
personasViewHolder.card_view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Toast.makeText(v.getContext(), "Eliminar Cardview", Toast.LENGTH_SHORT).show();
personasViewHolder.card_view.setBackgroundResource(R.color.colorPrimary);
globalPosition=i;
notifyDataSetChanged();
return false;
}
});
personasViewHolder.card_view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Reproducir", Toast.LENGTH_SHORT).show();
}
});
if(i==globalPosition)
{
//change color like
personasViewHolder.card_view.setBackgroundResource(R.color.colorPrimary);
}
else
{
personasViewHolder.card_view.setBackgroundResource(R.color.colorAccent);
}
}
#Override
public PersonasViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_layout_persona, viewGroup, false);
return new PersonasViewHolder(itemView);
}
public static class PersonasViewHolder extends RecyclerView.ViewHolder {
protected TextView txtNombre;
protected TextView txtUsuario;
protected TextView txtTwitter;
protected CardView card_view;
public PersonasViewHolder(View v) {
super(v);
txtNombre = (TextView) v.findViewById(R.id.txtNombre);
txtUsuario = (TextView) v.findViewById(R.id.txtUsuario);
txtTwitter = (TextView) v.findViewById(R.id.txtTwitter);
card_view = (CardView) v.findViewById(R.id.card_view);
}
}
//Metodo que nos retornarta la cantidad de personas en la lista
#Override
public int getItemCount() {
return personastList.size();
}
}

Categories

Resources