As you know, if we want to implement multiple types in RecyclerView
, we should provide multiple CustomViewHolder
extending RecyclerView.ViewHolder
.
For exmpale,
class TextViewHolder extends RecyclerView.ViewHolder{
TextView textView;
}
class ImageViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
}
Then we have to override getItemViewType
.And in onCreateViewHolder
to construct TextViewHolder
or ImageViewHolder
.
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
return new ImageViewHolder(mLayoutInflater.inflate(R.layout.item_image, parent, false));
} else {
return new TextViewHolder(mLayoutInflater.inflate(R.layout.item_text, parent, false));
}
}
Above code is normal but there is a another way.
I think only one CustomViewHolder
is enough.
class MultipleViewHolder extends RecyclerView.ViewHolder{
TextView textView;
ImageView imageView;
MultipleViewHolder(View itemView, int type){
if(type == 0){
textView = (TextView)itemView.findViewById(xx);
}else{
imageView = (ImageView)itemView.findViewById(xx);
}
}
}
Which way do you use in your developing work?
Android RecyclerView Multiple ViewType Project Structure We'll be implementing three view types (text, image, audio) that are inflated by three different layouts. Each has its own implementation specified in the adapter class.
The RecyclerView library provides three layout managers, which handle the most common layout situations: LinearLayoutManager arranges the items in a one-dimensional list.
Personally I like approach suggested by Yigit Boyar in this talk (fast forward to 31:07). Instead of returning a constant int from getItemViewType()
, return the layout id directly, which is also an int and is guaranteed to be unique:
@Override
public int getItemViewType(int position) {
switch (position) {
case 0:
return R.layout.first;
case 1:
return R.layout.second;
default:
return R.layout.third;
}
}
This will allow you to have following implementation in onCreateViewHolder()
:
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(viewType, parent, false);
MyViewHolder holder = null;
switch (viewType) {
case R.layout.first:
holder = new FirstViewHolder(view);
break;
case R.layout.second:
holder = new SecondViewHolder(view);
break;
case R.layout.third:
holder = new ThirdViewHolder(view);
break;
}
return holder;
}
Where MyViewHolder
is an abstract class:
public static abstract class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(View itemView) {
super(itemView);
// perform action specific to all viewholders, e.g.
// ButterKnife.bind(this, itemView);
}
abstract void bind(Item item);
}
And FirstViewHolder
is following:
public static class FirstViewHolder extends MyViewHolder {
@BindView
TextView title;
public FirstViewHolder(View itemView) {
super(itemView);
}
@Override
void bind(Item item) {
title.setText(item.getTitle());
}
}
This will make onBindViewHolder()
to be one-liner:
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.bind(dataList.get(holder.getAdapterPosition()));
}
Thus, you'd have each ViewHolder
separated, where bind(Item)
would be responsible to perform actions specific to that ViewHolder
only.
I like to use single responsability classes, as logic is not mixed.
Using the second example, you can quickly turn in spaguetti code, and if you like to check nullability, you are forced to declare "everything" as nullable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With