我正在尝试在我的应用中实现 RecyclerView。这是我的适配器类:
public class AdapterItemsList extends RecyclerView.Adapter<AdapterItemsList.ViewHolderItems>
{
private ArrayList<CItem> items;
public AdapterItemsList(ArrayList<CItem> items)
{
this.items = items;
}
@NonNull
@Override
public ViewHolderItems onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_counter, null, false);
return new ViewHolderItems(view);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolderItems holder, final int position)
{
holder.asignarDatos(items.get(holder.getAdapterPosition()));
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
//deleteSelectedItem() method gonna be here
Toast.makeText(view.getContext(), String.valueOf(holder.getAdapterPosition())
, Toast.LENGTH_SHORT).show();
return false;
}
});
holder.counterAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString());
auxInteger += 1;
holder.itemNumber.setText(auxInteger.toString());
items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString()));
}
});
holder.counterSubtract.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString());
if (auxInteger > 0)
{
auxInteger -= 1;
holder.itemNumber.setText(auxInteger.toString());
items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString()));
}
}
});
}
@Override
public int getItemCount()
{
return items.size();
}
public class ViewHolderItems extends RecyclerView.ViewHolder
{
TextView itemName;
TextView itemNumber;
Button counterAdd;
Button counterSubtract;
public ViewHolderItems(View itemView)
{
super(itemView);
itemName = (TextView) itemView.findViewById(R.id.textViewItemCounterName);
itemNumber = (TextView) itemView.findViewById(R.id.textViewItemCounterNumber);
counterAdd = (Button) itemView.findViewById(R.id.buttonItemCounterAdd);
counterSubtract = (Button) itemView.findViewById(R.id.buttonItemCounterSubtract);
}
public void asignarDatos(CItem item)
{
itemName.setText(item.getObjectName());
itemNumber.setText(item.getObjectNumber().toString());
}
}
}
“创建”适配器的代码:
private void CreateAdapter() {
recyclerViewItems.setAdapter(null);
items.clear();
//I dont post the code, but this just gets data from a SQLite database and populate "items".
LoadClientsList();
final AdapterItemsList adapter = new AdapterItemsList(items);
recyclerViewItems.setAdapter(adapter);
}
如您所见,我从不使用“implements View.OnLongClickListener”或类似的东西,但我只是在 onBindViewHolder 中设置 OnClickListener。现在里面有一个“ toast ”(当我测试应用程序时它看起来很好),但稍后,应该有我的“删除项目”对话框,它会让用户更改为接受或取消(一个通常的对话框) .如果用户按下“接受”,那么我将从列表中删除该项目。
我承认,我不是 Android 或 Java 忍者,所以我知道可能会出现可怕的错误。但问题是,该应用程序现在正在运行(当我长按一个项目时 Toast 正确显示),但事实上我从不使用“工具”,而我看到每个人都在与 RecyclerViews 和适配器相关的 StackOverflow 问题中这样做,让我觉得我犯了(几个)严重的错误。
我可以承认,因为我不是 Java 基础知识的专家(我已经使用 COBOL 工作了几年,我几乎记得 OOP 是 NULL),所以我看不出我的错误在哪里,但仍然非常感谢任何帮助。
谢谢!
更新: 好的,我正在更改我的代码,现在如下所示:
public class AdapterItemsList extends RecyclerView.Adapter<AdapterItemsList.ViewHolderItems> implements View.OnClickListener { private ArrayList<CItem> items; /* Added this */ private View.OnClickListener listener; public AdapterItemsList(ArrayList<CItem> items) { this.items = items; } @NonNull @Override public ViewHolderItems onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_counter, null, false); /* Added this */ view.setOnClickListener(this); return new ViewHolderItems(view); } @Override public void onBindViewHolder(@NonNull final ViewHolderItems holder, final int position) { holder.asignarDatos(items.get(holder.getAdapterPosition())); holder.counterAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString()); auxInteger += 1; holder.itemNumber.setText(auxInteger.toString()); items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString())); } }); holder.counterSubtract.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString()); if (auxInteger > 0) { auxInteger -= 1; holder.itemNumber.setText(auxInteger.toString()); items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString())); } } }); } @Override public int getItemCount() { [...] } /* Added this */ public void setOnClickListener(View.OnClickListener listener) { this.listener = listener; } /* Added this */ @Override public void onClick(View view) { if (listener != null) { listener.onClick(view); } } public class ViewHolderItems extends RecyclerView.ViewHolder { [...] } }
我创建适配器的代码:
private void CreateAdapter() { recyclerViewItems.setAdapter(null); items.clear(); LoadClientsList(); final AdapterItemsList adapter = new AdapterItemsList(items); /* Added this */ adapter.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(getApplicationContext(), String.valueOf(recyclerViewItems.getChildAdapterPosition(view)), Toast.LENGTH_SHORT).show(); } }); recyclerViewItems.setAdapter(adapter); }
“recyclerViewItems.getChildAdapterPosition(view)”终于解决了我的问题(之前没有提到,但这是我将“setOnClick ...”放在onBindViewHolder方法中的原因,只是因为我需要的位置按下的项目,我无法弄清楚到底如何访问它)。 所以现在我在创建适配器时设置监听器,而不是在绑定(bind) View 持有者时设置监听器,我想这样更好。 不过,我没有更改“holder.counterAdd.setOnClickListener”和“holder.counterSubtract.setOnClickListener”行,因为我认为它们必须在 onBindViewHolder 方法中,但我想我还是错了。
最佳答案
我不同意对您问题的大部分评论,而且我认为您编写适配器的方式非常好。它并不完美,但是手动将 View.OnClickListener
设置为您的 ViewHolder
中的一些(或许多) View 并没有错。事实上,这是 Google 推荐的做事方式!
不过,我会做出一些改变。第一种方法是将点击监听器的声明移动到 onCreateViewHolder()
方法中(通过将它们放在 ViewHolder 的构造函数中)。第二种方法是添加对 NO_POSITION
的检查,以确保您处理从适配器中删除项目但尚未重新计算布局的情况。
这是我的建议:
public ViewHolderItems(View itemView)
{
super(itemView);
itemName = (TextView) itemView.findViewById(R.id.textViewItemCounterName);
itemNumber = (TextView) itemView.findViewById(R.id.textViewItemCounterNumber);
counterAdd = (Button) itemView.findViewById(R.id.buttonItemCounterAdd);
counterSubtract = (Button) itemView.findViewById(R.id.buttonItemCounterSubtract);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
deleteItem();
return true;
}
});
counterAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
itemAdd();
}
});
counterSubtract.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
itemSubtract();
}
});
}
private void deleteItem() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
items.remove(position);
adapter.notifyItemRemoved(position);
}
}
private void itemAdd() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
CItem item = items.get(position);
item.setObjectNumber(item.getObjectNumber() + 1);
adapter.notifyItemChanged(position);
}
}
private void itemSubtract() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
CItem item = items.get(position);
if (item.getObjectNumber() > 0) {
item.setObjectNumber(item.getObjectNumber() - 1);
adapter.notifyItemChanged(position);
}
}
}
然后你的 onBindViewHolder()
非常简单:
@Override
public void onBindViewHolder(@NonNull ViewHolderItems holder, int position)
{
holder.asignarDatos(items.get(position));
}
那么,让我们谈谈我在这里做什么。
首先,我将所有监听器设置推送到 ViewHolder 的构造函数中。这意味着监听器都被分配了一次。为了在 ViewHolders 被回收并附加到不同项目的世界中仍然发挥作用,我们必须使用 getAdapterPosition()
来确保我们始终与列表中的正确项目进行交互.
我们必须检查 NO_POSITION
因为 RecyclerView 布局操作是异步的:当你从列表中删除一个项目时,有一个间隙,该项目不再存在于你的适配器中但仍然存在显示在屏幕上。在这个间隙中,用户可能会点击一个按钮!在这些情况下,我们只是忽略用户输入。
我还更改了更新项目值的方式以及显示这些更新的方式。我不是获取文本并解析它然后重新设置它,而是总是通过适配器。请记住,您的 RecyclerView 实现的目标是能够正确显示列表中的任何元素。执行此操作的最佳方法是更新数据集中的元素,然后通知 RecyclerView 该元素已更改,并让 onBindViewHolder()
处理所需的更新。
关于android - 这是在 Android 中实现 RecyclerView 的错误方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58919337/