如何使用数据绑定在 RecyclerView 中添加 onClickListener
How to add an onClickListener in RecyclerView using data binding
我刚开始使用 databinding
,现在我被困在 数据绑定 方式 recyclerView
中实现点击监听器。
我让它像这样工作:
@NonNull
@Override
public BookViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemBookCoversBinding binding = ItemBookCoversBinding.inflate(LayoutInflater.from(context), parent, false);
final BookViewHolder bookViewHolder = new BookViewHolder(binding);
bookViewHolder.binding.bookDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.deleteCover(bookViewHolder.getAdapterPosition());
}
});
bookViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.changeCover(bookViewHolder.getAdapterPosition());
}
});
return bookViewHolder;
}
确实可以正常工作,但我没有将 databinding
用于 clickListener
。
我试过像这样在我的布局中添加一个可变位置:
<data>
<variable
name="position"
type="int" />
<variable
name="listener"
type="....interfaces.Listener" />
</data>
<ImageView
android:id="@+id/book_cover"
coverImage="@{bookImages.storageRef}"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_green_dark"
android:onClick="@{() -> listener.changeCover(position)}"
android:src="@drawable/placeholder" />
并且在适配器中的 onCreateViewHolder
中:
bookViewHolder.binding.setVariable(BR.position, bookViewHolder.getAdapterPosition());
或者这个:
binding.setPosition(bookViewHolder.getAdapterPosition());
onClick
在两种情况下都按预期工作,但 bookViewHolder.getAdapterPosition()
returns -1
,NO_POSITION
我在这里错过了什么?
在 RecyclerView
中实现 databinding
onClickListener
的最佳方法是什么?
我已经有了一些有用的东西,但不是 databinding
的方法。
它不起作用,因为您在视图创建时分配了变量。目前您的 ViewHolder
没有 adapterPositions。我不知道它们究竟是如何工作的,但每当我尝试在点击监听器之外使用它时,它总是返回 -1。它们此时没有附加到 RecyclerView
,因此如果没有一些异步工作或 layoutChangeListeners 就无法获得它,并且它可能在 onCreateViewHolder
中始终为 -1
解决方法是从其他地方获取您的 ViewHolder
位置。在覆盖 getItemViewType(int pos)
方法后,您可以使用 viewType
变量获得此信息:
@Override
public int getItemViewType(int position) {
return position;
}
@NonNull
@Override
public PlaylistViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewTypeButActuallyItIsPosition) {
...
binding.setPosition(viewTypeButActuallyItIsPosition);
...
}
编辑
您使用这种方法可能面临的一个问题(在我看来您可能会遇到)是当您的 ViewHolders
被回收时 ImageView
s 将设置错误的位置,因为 onBindViewHolder
方法将在不调用 onCreateViewHolder
的情况下被调用,UI 将被更改但绑定变量将保持不变,因此正确的方法是在 onBindViewHolder
方法中分配此位置。这意味着您应该将绑定保留在 ViewHolder
class 中并将其保留在 public 中,以便您可以在 onBindViewHolder
中访问它
@Override
public void onBindViewHolder(@NonNull YourViewHolder holder, int i) {
...
holder.binding.setPosition(i);
}
似乎当您在适配器中执行 data binding
时,您想要设置将触发 clickListener
的变量以及您选择填充每个项目的数据绑定方法。
因为它是一个变量,而不是一个方法。
在适配器中实施点击侦听器是开发人员的样板代码。
- 您应该在适配器中创建接口并从 activity/Fragment 实现它,并从 xml 文件调用它,因为您希望与数据绑定集成。
我刚开始使用 databinding
,现在我被困在 数据绑定 方式 recyclerView
中实现点击监听器。
我让它像这样工作:
@NonNull
@Override
public BookViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemBookCoversBinding binding = ItemBookCoversBinding.inflate(LayoutInflater.from(context), parent, false);
final BookViewHolder bookViewHolder = new BookViewHolder(binding);
bookViewHolder.binding.bookDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.deleteCover(bookViewHolder.getAdapterPosition());
}
});
bookViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.changeCover(bookViewHolder.getAdapterPosition());
}
});
return bookViewHolder;
}
确实可以正常工作,但我没有将 databinding
用于 clickListener
。
我试过像这样在我的布局中添加一个可变位置:
<data>
<variable
name="position"
type="int" />
<variable
name="listener"
type="....interfaces.Listener" />
</data>
<ImageView
android:id="@+id/book_cover"
coverImage="@{bookImages.storageRef}"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_green_dark"
android:onClick="@{() -> listener.changeCover(position)}"
android:src="@drawable/placeholder" />
并且在适配器中的 onCreateViewHolder
中:
bookViewHolder.binding.setVariable(BR.position, bookViewHolder.getAdapterPosition());
或者这个:
binding.setPosition(bookViewHolder.getAdapterPosition());
onClick
在两种情况下都按预期工作,但 bookViewHolder.getAdapterPosition()
returns -1
,NO_POSITION
我在这里错过了什么?
在 RecyclerView
中实现 databinding
onClickListener
的最佳方法是什么?
我已经有了一些有用的东西,但不是 databinding
的方法。
它不起作用,因为您在视图创建时分配了变量。目前您的 ViewHolder
没有 adapterPositions。我不知道它们究竟是如何工作的,但每当我尝试在点击监听器之外使用它时,它总是返回 -1。它们此时没有附加到 RecyclerView
,因此如果没有一些异步工作或 layoutChangeListeners 就无法获得它,并且它可能在 onCreateViewHolder
解决方法是从其他地方获取您的 ViewHolder
位置。在覆盖 getItemViewType(int pos)
方法后,您可以使用 viewType
变量获得此信息:
@Override
public int getItemViewType(int position) {
return position;
}
@NonNull
@Override
public PlaylistViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewTypeButActuallyItIsPosition) {
...
binding.setPosition(viewTypeButActuallyItIsPosition);
...
}
编辑
您使用这种方法可能面临的一个问题(在我看来您可能会遇到)是当您的 ViewHolders
被回收时 ImageView
s 将设置错误的位置,因为 onBindViewHolder
方法将在不调用 onCreateViewHolder
的情况下被调用,UI 将被更改但绑定变量将保持不变,因此正确的方法是在 onBindViewHolder
方法中分配此位置。这意味着您应该将绑定保留在 ViewHolder
class 中并将其保留在 public 中,以便您可以在 onBindViewHolder
@Override
public void onBindViewHolder(@NonNull YourViewHolder holder, int i) {
...
holder.binding.setPosition(i);
}
似乎当您在适配器中执行 data binding
时,您想要设置将触发 clickListener
的变量以及您选择填充每个项目的数据绑定方法。
因为它是一个变量,而不是一个方法。
在适配器中实施点击侦听器是开发人员的样板代码。
- 您应该在适配器中创建接口并从 activity/Fragment 实现它,并从 xml 文件调用它,因为您希望与数据绑定集成。