具有多种 ViewHolder 类型的 RecyclerView
RecyclerView with multiple ViewHolder types
在 GalleryFragment
中,我显示了用户图库中的所有图像,我在位置 0 处有一个按钮,该按钮可以通过相机拍摄新图像。
我正在像这样传递列表中的第一个数据galleryModelList.add(new GalleryModel(null, null, null));
我这样做是因为我想先显示按钮然后显示其他图像。
public class GalleryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<GalleryModel> galleryModelList;
public GalleryAdapter(List<GalleryModel> galleryModelList) {
this.galleryModelList = galleryModelList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == 0)
return new NewImageViewHolder(RowNewImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
else
return new GalleryViewHolder(RowGalleryBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == 0) {
//...
} else {
//...
}
}
@Override
public int getItemCount() {
return galleryModelList.size();
}
@Override
public int getItemViewType(int position) {
return position;
}
public static class NewImageViewHolder extends RecyclerView.ViewHolder {
RowNewImageBinding rowNewImageBinding;
public NewImageViewHolder(@NonNull RowNewImageBinding rowNewImageBinding) {
super(rowNewImageBinding.getRoot());
this.rowNewImageBinding = rowNewImageBinding;
}
}
public static class GalleryViewHolder extends RecyclerView.ViewHolder {
RowGalleryBinding rowGalleryBinding;
public GalleryViewHolder(@NonNull RowGalleryBinding rowGalleryBinding) {
super(rowGalleryBinding.getRoot());
this.rowGalleryBinding = rowGalleryBinding;
}
}
}
一切正常,但我想问一下,像我上面做的那样将空值传递到第一个位置是不是一种好方法,或者有更好的方法来显示按钮而不传递假数据?
编辑 2022 年 2 月 16 日
snachmsm的答案是正确的,但我做了一些修改,这是结果
当我点击按钮旁边的项目时,出现此错误 java.lang.ClassCastException: com.test.app.adapters.GalleryAdapter$NewImageViewHolder cannot be cast to com.test.app.adapters.GalleryAdapter$GalleryViewHolder
错误来自这里
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty())
super.onBindViewHolder(holder, position, payloads);
else
((GalleryViewHolder) holder).rowGalleryBinding.rowGalleryCounter.setText(String.valueOf(payloads.get(0)));
}
这是完整的 GalleryAdapter 文件
public class GalleryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<GalleryModel> galleryModelList;
private final List<Integer> selectedItems = new ArrayList<>();
public GalleryAdapter(List<GalleryModel> galleryModelList) {
this.galleryModelList = galleryModelList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == 0)
return new NewImageViewHolder(RowNewImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
else
return new GalleryViewHolder(RowGalleryBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == 0) {
//soon
} else {
int realPosition = position - 1;
GalleryViewHolder galleryViewHolder = (GalleryViewHolder) holder;
galleryViewHolder.rowGalleryBinding.setGalleryModel(galleryModelList.get(realPosition));
if (selectedItems.contains(realPosition)) {
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setText(String.valueOf(selectedItems.indexOf(realPosition) + 1));
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setVisibility(View.VISIBLE);
} else
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setVisibility(View.GONE);
galleryViewHolder.rowGalleryBinding.rowGalleryContainer.setOnClickListener(view -> {
if (selectedItems.contains(realPosition)) {
selectedItems.remove((Integer) realPosition);
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setVisibility(View.GONE);
} else {
selectedItems.add(realPosition);
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setText(String.valueOf(selectedItems.indexOf(realPosition) + 1));
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setVisibility(View.VISIBLE);
}
for (int i = 0; i < selectedItems.size(); i++)
notifyItemChanged(selectedItems.get(i), selectedItems.indexOf(selectedItems.get(i)) + 1);
});
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty())
super.onBindViewHolder(holder, position, payloads);
else
((GalleryViewHolder) holder).rowGalleryBinding.rowGalleryCounter.setText(String.valueOf(payloads.get(0)));
}
@Override
public int getItemCount() {
return galleryModelList.size() + 1;
}
@Override
public int getItemViewType(int position) {
return position;
}
public static class NewImageViewHolder extends RecyclerView.ViewHolder {
RowNewImageBinding rowNewImageBinding;
public NewImageViewHolder(@NonNull RowNewImageBinding rowNewImageBinding) {
super(rowNewImageBinding.getRoot());
this.rowNewImageBinding = rowNewImageBinding;
}
}
public static class GalleryViewHolder extends RecyclerView.ViewHolder {
RowGalleryBinding rowGalleryBinding;
public GalleryViewHolder(@NonNull RowGalleryBinding rowGalleryBinding) {
super(rowGalleryBinding.getRoot());
this.rowGalleryBinding = rowGalleryBinding;
}
}
}
下面的答案和我之前说的一样完美,但在我做了一些更改后,我遇到了上面的错误,我不知道如何解决它。
你不应该那样做,这个 single/first 项目不是 collection 成员。不要添加这个虚拟视图,而是通知适配器有一个额外的项目
private static final int EXTRA_ITEMS_ON_TOP = 1; // num of buttons
private static final int TYPE_BUTTON = 0;
private static final int TYPE_LIST_ITEM =1;
@Override
public int getItemCount() {
return galleryModelList.size() + EXTRA_ITEMS_ON_TOP;
}
@Override
public int getItemViewType(int position) {
// return TYPE_BUTTON type first position(s)
return position < EXTRA_ITEMS_ON_TOP ? TYPE_BUTTON : TYPE_LIST_ITEM;
}
在onBindViewHolder
里面只是重新计算位置
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == TYPE_BUTTON) {
//... position < EXTRA_ITEMS_ON_TOP, so 0 only in current config
} else {
int realPosition = position - EXTRA_ITEMS_ON_TOP;
GalleryModel model = galleryModelList.get(realPosition);
...
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_BUTTON)
return new NewImageViewHolder(RowNewImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
else
return new GalleryViewHolder(RowGalleryBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
您当前的方法是一种解决方法。它可能有效,但您可能还想从适配器获取完整列表,您将获得一个包含一个额外项目(虚拟项目)的列表,并且当它用 null
s 完成时,您可能会得到一些 NullPointerException
。为了解决这个问题,你可能会做一些 if
,这会使下一个地方的代码复杂化
在 GalleryFragment
中,我显示了用户图库中的所有图像,我在位置 0 处有一个按钮,该按钮可以通过相机拍摄新图像。
我正在像这样传递列表中的第一个数据galleryModelList.add(new GalleryModel(null, null, null));
我这样做是因为我想先显示按钮然后显示其他图像。
public class GalleryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<GalleryModel> galleryModelList;
public GalleryAdapter(List<GalleryModel> galleryModelList) {
this.galleryModelList = galleryModelList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == 0)
return new NewImageViewHolder(RowNewImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
else
return new GalleryViewHolder(RowGalleryBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == 0) {
//...
} else {
//...
}
}
@Override
public int getItemCount() {
return galleryModelList.size();
}
@Override
public int getItemViewType(int position) {
return position;
}
public static class NewImageViewHolder extends RecyclerView.ViewHolder {
RowNewImageBinding rowNewImageBinding;
public NewImageViewHolder(@NonNull RowNewImageBinding rowNewImageBinding) {
super(rowNewImageBinding.getRoot());
this.rowNewImageBinding = rowNewImageBinding;
}
}
public static class GalleryViewHolder extends RecyclerView.ViewHolder {
RowGalleryBinding rowGalleryBinding;
public GalleryViewHolder(@NonNull RowGalleryBinding rowGalleryBinding) {
super(rowGalleryBinding.getRoot());
this.rowGalleryBinding = rowGalleryBinding;
}
}
}
一切正常,但我想问一下,像我上面做的那样将空值传递到第一个位置是不是一种好方法,或者有更好的方法来显示按钮而不传递假数据?
编辑 2022 年 2 月 16 日
snachmsm的答案是正确的,但我做了一些修改,这是结果
当我点击按钮旁边的项目时,出现此错误 java.lang.ClassCastException: com.test.app.adapters.GalleryAdapter$NewImageViewHolder cannot be cast to com.test.app.adapters.GalleryAdapter$GalleryViewHolder
错误来自这里
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty())
super.onBindViewHolder(holder, position, payloads);
else
((GalleryViewHolder) holder).rowGalleryBinding.rowGalleryCounter.setText(String.valueOf(payloads.get(0)));
}
这是完整的 GalleryAdapter 文件
public class GalleryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<GalleryModel> galleryModelList;
private final List<Integer> selectedItems = new ArrayList<>();
public GalleryAdapter(List<GalleryModel> galleryModelList) {
this.galleryModelList = galleryModelList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == 0)
return new NewImageViewHolder(RowNewImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
else
return new GalleryViewHolder(RowGalleryBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == 0) {
//soon
} else {
int realPosition = position - 1;
GalleryViewHolder galleryViewHolder = (GalleryViewHolder) holder;
galleryViewHolder.rowGalleryBinding.setGalleryModel(galleryModelList.get(realPosition));
if (selectedItems.contains(realPosition)) {
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setText(String.valueOf(selectedItems.indexOf(realPosition) + 1));
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setVisibility(View.VISIBLE);
} else
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setVisibility(View.GONE);
galleryViewHolder.rowGalleryBinding.rowGalleryContainer.setOnClickListener(view -> {
if (selectedItems.contains(realPosition)) {
selectedItems.remove((Integer) realPosition);
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setVisibility(View.GONE);
} else {
selectedItems.add(realPosition);
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setText(String.valueOf(selectedItems.indexOf(realPosition) + 1));
galleryViewHolder.rowGalleryBinding.rowGalleryCounter.setVisibility(View.VISIBLE);
}
for (int i = 0; i < selectedItems.size(); i++)
notifyItemChanged(selectedItems.get(i), selectedItems.indexOf(selectedItems.get(i)) + 1);
});
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty())
super.onBindViewHolder(holder, position, payloads);
else
((GalleryViewHolder) holder).rowGalleryBinding.rowGalleryCounter.setText(String.valueOf(payloads.get(0)));
}
@Override
public int getItemCount() {
return galleryModelList.size() + 1;
}
@Override
public int getItemViewType(int position) {
return position;
}
public static class NewImageViewHolder extends RecyclerView.ViewHolder {
RowNewImageBinding rowNewImageBinding;
public NewImageViewHolder(@NonNull RowNewImageBinding rowNewImageBinding) {
super(rowNewImageBinding.getRoot());
this.rowNewImageBinding = rowNewImageBinding;
}
}
public static class GalleryViewHolder extends RecyclerView.ViewHolder {
RowGalleryBinding rowGalleryBinding;
public GalleryViewHolder(@NonNull RowGalleryBinding rowGalleryBinding) {
super(rowGalleryBinding.getRoot());
this.rowGalleryBinding = rowGalleryBinding;
}
}
}
下面的答案和我之前说的一样完美,但在我做了一些更改后,我遇到了上面的错误,我不知道如何解决它。
你不应该那样做,这个 single/first 项目不是 collection 成员。不要添加这个虚拟视图,而是通知适配器有一个额外的项目
private static final int EXTRA_ITEMS_ON_TOP = 1; // num of buttons
private static final int TYPE_BUTTON = 0;
private static final int TYPE_LIST_ITEM =1;
@Override
public int getItemCount() {
return galleryModelList.size() + EXTRA_ITEMS_ON_TOP;
}
@Override
public int getItemViewType(int position) {
// return TYPE_BUTTON type first position(s)
return position < EXTRA_ITEMS_ON_TOP ? TYPE_BUTTON : TYPE_LIST_ITEM;
}
在onBindViewHolder
里面只是重新计算位置
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == TYPE_BUTTON) {
//... position < EXTRA_ITEMS_ON_TOP, so 0 only in current config
} else {
int realPosition = position - EXTRA_ITEMS_ON_TOP;
GalleryModel model = galleryModelList.get(realPosition);
...
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_BUTTON)
return new NewImageViewHolder(RowNewImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
else
return new GalleryViewHolder(RowGalleryBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
您当前的方法是一种解决方法。它可能有效,但您可能还想从适配器获取完整列表,您将获得一个包含一个额外项目(虚拟项目)的列表,并且当它用 null
s 完成时,您可能会得到一些 NullPointerException
。为了解决这个问题,你可能会做一些 if
,这会使下一个地方的代码复杂化