Hudi Ilfeld
Hudi Ilfeld

Reputation: 2045

OnClick for item in RecyclerView

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:

  1. Add the current item's data to an ArrayList [displayed on a different Fragment]

  2. Display a Toast to the user.

  3. modify the UI of the selected item. [i.e setVisibility of Button to 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.

  1. How do I prevent this behavior?
  2. Why is this behavior occurring with the 3rd task only?

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

Answers (2)

Hudi Ilfeld
Hudi Ilfeld

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

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

Related Questions