Home > Enterprise >  RecyclerView with multiple ViewHolder types
RecyclerView with multiple ViewHolder types

Time:02-16

In GalleryFragment I'm showing all images from the user gallery and I have a button at position 0, The button can do take new images via the camera.

I'm passing the first data in the list like this galleryModelList.add(new GalleryModel(null, null, null));

I did that because I want to show the button firstly then show else images.

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

    }

}

Everything works well but I want to ask is it a good way to pass null values to the first position like what I did above or there is a better way to show the button without passing fake data?

CodePudding user response:

you shouldn't do this that way, this single/first item isn't a collection member. don't add this dummy view, instead inform adapter that there is one extra item

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

and inside onBindViewHolder just recalculate position

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

your current way is kind of workaround. it may work, but further you may want to obtain full list from adapter and you will get list with one extra item (dummy one) and as it is fulfilled with nulls you may get some NullPointerException. for fixing this you will probably make some if, which complicates code in next place

  • Related