RecyclerView 中的项目的 OnClick

OnClick for item in RecyclerView

我目睹了 RecyclerView 的奇怪行为。所以我在 Button 上的 ViewHolder 中设置了一个 OnClickListener,当用户单击时,它打算做 3 件事:

  1. 将当前项目的数据添加到ArrayList[显示在不同的Fragment]

  2. 向用户显示一个Toast

  3. 修改所选项目的UI。 [即将 Button 的 Visibility 设置为 View.INVISIBLE 等。]

现在,虽然 OnClickListener 的前两个任务已成功完成并且 应用于所选项目,但第三个任务旨在修改 UI 仅 选定的 项,而是也应用于 RecyclerView 上的每个第 9 项。

  1. 如何防止这种行为?
  2. 为什么仅在第 3 个任务中出现此行为?

i.e 来自之前的回答。我看到的特定主题,我认为最好在 ViewHolder 中插入 OnClickListener 而不是将其放入 onBindViewHolder,这并没有解决问题。我遵循了 Whosebug 上的其他建议,但都失败了。

这是我的代码:

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()));
                }
            });
        }
    }

  }

我认为 getAdapterPosition() 导致了问题。请尝试在 viewholder 中创建一个新的 int 属性 positiononBindViewHolder 将位置传递给 viewholder,holder.position = position,并在您的 viewholder 中使用该位置,因此将是 int pos = position 而不是 getAdapterPosition()

在每次点击一个项目时,我将实例化对象中的一个布尔值分配给 true,然后我 运行 notifyDataSetChanged() 其中。使用具有 boolean true 的数据对象更新所有项目。通过这种方式,我确保 所选对象将被更新。

看起来像这样:

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);
        }
    }