RecyclerView 中的项目的 OnClick
OnClick for item in RecyclerView
我目睹了 RecyclerView
的奇怪行为。所以我在 Button
上的 ViewHolder
中设置了一个 OnClickListener,当用户单击时,它打算做 3 件事:
将当前项目的数据添加到ArrayList
[显示在不同的Fragment
]
向用户显示一个Toast
。
- 修改所选项目的UI。 [即将 Button 的 Visibility 设置为
View.INVISIBLE
等。]
现在,虽然 OnClickListener
的前两个任务已成功完成并且 仅 应用于所选项目,但第三个任务旨在修改 UI 仅 选定的 项,而是也应用于 RecyclerView
上的每个第 9 项。
- 如何防止这种行为?
- 为什么仅在第 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 属性 position
,onBindViewHolder
将位置传递给 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);
}
}
我目睹了 RecyclerView
的奇怪行为。所以我在 Button
上的 ViewHolder
中设置了一个 OnClickListener,当用户单击时,它打算做 3 件事:
将当前项目的数据添加到
ArrayList
[显示在不同的Fragment
]向用户显示一个
Toast
。- 修改所选项目的UI。 [即将 Button 的 Visibility 设置为
View.INVISIBLE
等。]
现在,虽然 OnClickListener
的前两个任务已成功完成并且 仅 应用于所选项目,但第三个任务旨在修改 UI 仅 选定的 项,而是也应用于 RecyclerView
上的每个第 9 项。
- 如何防止这种行为?
- 为什么仅在第 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 属性 position
,onBindViewHolder
将位置传递给 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);
}
}