Reputation: 2045
I am witnessing a wierd behavior of RecyclerView
. so I have set an OnClickListener in the ViewHolder
on a Button
which is meant to do 3 things, when the user clicks:
Add the current item's data to an ArrayList
[displayed on a different Fragment
]
Display a Toast
to the user.
View.INVISIBLE
etc..]now, while the first two tasks of the OnClickListener
are fulfilled successfully and apply only to the selected item, the third one which is meant to modify the UI of the selected item only, instead gets also applied to each 9th Item on the RecyclerView
.
i.e from previous answers on this. particular topic that I saw, I got the notion that it's better to insert the OnClickListener
in the ViewHolder
rather then putting it in onBindViewHolder
, which did not solve the issue. I have followed other suggestions on stackOverflow and all failed.
Here is my code:
static class ItemsRecyclerAdapter extends RecyclerView.Adapter<ItemsRecyclerAdapter.ItemsViewHolder>{
FragmentActivity fragmentActivity;
List<ProductItem> data;
LayoutInflater inflater;
private int id;
private int shopCode;
public ItemsRecyclerAdapter(List<ProductItem> data, FragmentActivity fragmentActivity, int id, int shopCode) {
this.fragmentActivity = fragmentActivity;
this.data = data;
this.inflater = LayoutInflater.from(fragmentActivity);
this.id = id;
this.shopCode = shopCode;
}
@Override
public ItemsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = inflater.inflate(R.layout.pricing_item, parent, false);
return new ItemsViewHolder(v);
}
@Override
public void onBindViewHolder(final ItemsViewHolder holder, int position) {
ProductItem itemPrice = data.get(position);
holder.productName.setText(itemPrice.getProductName());
holder.quantity.setText(itemPrice.getProductQuantity());
holder.tvPrice.setText(itemPrice.getproductPrice());
Picasso.with(fragmentActivity).load(itemPrice.getThumbUrl()).into(holder.imgProduct);
}
@Override
public int getItemCount() {
return data.size();
}
class ItemsViewHolder extends RecyclerView.ViewHolder{
TextView productName, quantity, tvPrice;
ImageView imgProduct;
Button btnAddToBasket, btnAdd, btnRemove;
Typeface myCustomFont = Typeface.createFromAsset(fragmentActivity.getAssets(), "fonts/Assistant-SemiBold.ttf");
public ItemsViewHolder(View itemView) {
super(itemView);
productName = (TextView) itemView.findViewById(R.id.productName);
quantity = (TextView) itemView.findViewById(R.id.manufacturer);
tvPrice = (TextView) itemView.findViewById(R.id.tvPrice);
imgProduct = (ImageView) itemView.findViewById(R.id.imgProduct);
btnAddToBasket = (Button) itemView.findViewById(R.id.btnAddToBasket);
btnAdd = itemView.findViewById(R.id.btnAdd);
btnRemove = itemView.findViewById(R.id.btnRemove);
btnAdd.setVisibility(View.INVISIBLE);
btnRemove.setVisibility(View.INVISIBLE);
quantity.setTypeface(myCustomFont);
productName.setTypeface(myCustomFont);
tvPrice.setTypeface(myCustomFont);
Typeface fontAwesomeBasketIcon = Typeface.createFromAsset(fragmentActivity.getAssets(), "fontawesome-webfont.ttf");
btnAddToBasket.setTypeface(fontAwesomeBasketIcon);
btnAdd.setTypeface(fontAwesomeBasketIcon);
btnRemove.setTypeface(fontAwesomeBasketIcon);
btnAddToBasket.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = getAdapterPosition();
MyBasketFragment.myBasketList
.add(new ProductItem(data.get(pos).getProductName(), data.get(pos).getProductQuantity(),
data.get(pos).getproductPrice(), data.get(pos).getThumbUrl(), id, shopCode));
btnAddToBasket.setOnClickListener(null);
Toast.makeText(fragmentActivity, "New product..", Toast.LENGTH_SHORT).show();
btnAdd.setVisibility(View.VISIBLE);
btnRemove.setVisibility(View.VISIBLE);
}
});
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ItemsFragment.atomic.incrementAndGet();
btnAddToBasket.setText(String.valueOf(atomic.get()));
}
});
}
}
}
Upvotes: 0
Views: 1809
Reputation: 2045
On every Click of an item, I assign a boolean in the instantiated object to true and and then I run notifyDataSetChanged()
which. updates all items with data objects which have a boolean
true. this way I'm ensuring that only the selected object will be updated.
It looks something like this:
ViewHolder
class ItemsViewHolder extends RecyclerView.ViewHolder {
TextView productName, quantity, tvPrice;
ImageView imgProduct;
Button btnAddToBasket, btnAdd, btnRemove;
Typeface myCustomFont = Typeface.createFromAsset(fragmentActivity.getAssets(), "fonts/Assistant-SemiBold.ttf");
public ItemsViewHolder(View itemView) {
super(itemView);
productName = (TextView) itemView.findViewById(R.id.productName);
quantity = (TextView) itemView.findViewById(R.id.manufacturer);
tvPrice = (TextView) itemView.findViewById(R.id.tvPrice);
imgProduct = (ImageView) itemView.findViewById(R.id.imgProduct);
btnAddToBasket = (Button) itemView.findViewById(R.id.btnAddToBasket);
btnAdd = itemView.findViewById(R.id.btnAdd);
btnRemove = itemView.findViewById(R.id.btnRemove);
btnAdd.setVisibility(View.INVISIBLE);
btnRemove.setVisibility(View.INVISIBLE);
quantity.setTypeface(myCustomFont);
productName.setTypeface(myCustomFont);
tvPrice.setTypeface(myCustomFont);
Typeface fontAwesomeBasketIcon = Typeface.createFromAsset(fragmentActivity.getAssets(), "fontawesome-webfont.ttf");
btnAddToBasket.setTypeface(fontAwesomeBasketIcon);
btnAdd.setTypeface(fontAwesomeBasketIcon);
btnRemove.setTypeface(fontAwesomeBasketIcon);
}
public void bind(final ProductItem item) {
btnAddToBasket.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
item.clicked = true;
item.atomic.incrementAndGet();
Toast.makeText(fragmentActivity, "New product..", Toast.LENGTH_SHORT).show();
notifyDataSetChanged();
MyBasketFragment.myBasketList
.add(new ProductItem(item.getProductName(), item.getProductQuantity(),
item.getproductPrice(), item.getThumbUrl(), id, shopCode));
}
});
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ItemsFragment.atomic.incrementAndGet();
btnAddToBasket.setText(String.valueOf(atomic.get()));
}
});
}
}
onBindViewHolder
@Override
public void onBindViewHolder(final ItemsViewHolder holder, final int position) {
ProductItem itemPrice = data.get(position);
holder.productName.setText(itemPrice.getProductName());
holder.quantity.setText(itemPrice.getProductQuantity());
holder.tvPrice.setText(itemPrice.getproductPrice());
Picasso.with(fragmentActivity).load(itemPrice.getThumbUrl()).into(holder.imgProduct);
holder.bind(itemPrice);
if(itemPrice.clicked){
holder.btnAddToBasket.setOnClickListener(null);
holder.btnAddToBasket.setText(String.valueOf(atomic.get()));
holder.btnAdd.setVisibility(View.VISIBLE);
holder.btnRemove.setVisibility(View.VISIBLE);
} else {
holder.btnAddToBasket.setText("\uf291");
holder.btnAdd.setVisibility(View.INVISIBLE);
holder.btnRemove.setVisibility(View.INVISIBLE);
}
}
Upvotes: 2
Reputation: 5481
I think getAdapterPosition()
is causing the problem. Please, try creating a new int attribute position
in the viewholder, onBindViewHolder
pass the the position to the viewholder, holder.position = position
, and in your viewholder use the position, so will be int pos = position
instead of getAdapterPosition()
Upvotes: 0