Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create RecyclerView item layout based on content of data

I'm creating a recycler view of data objects, each of these object will vary, eg.

Obj 1 - String Heading - String Desc - Image

Obj 2 - String Desc

Obj 3 - Image - String Link

Obj 4 - String Desc - Video

etc

So I need to create my item layout dynamically to suit each data object. I don't want to create an item layout with all the possible views and components and show and hide as I feel it's bad practice.

So my issue is I need to access an object from the list using the position in the onBindViewHolder in order to construct my layout in the ViewHolder class.

I tried using a method which I called in the onBindViewHolder class and passed in the object in which I added custom views to an array, setting the content inside at the same time but this didn't work.

Does anyone know how this can be done?

Regards

like image 852
DJ-DOO Avatar asked Mar 16 '23 00:03

DJ-DOO


1 Answers

first you proper implement view type like explained here How to create RecyclerView with multiple view type? actually, your question is duplicated of that, but I'll just write some extra organization stuff to help you deal with larger quantity of holders.

  • on this answer I'll be using ButterKnife and Picasso libraris because they're awesome: http://jakewharton.github.io/butterknife/ and http://square.github.io/picasso/

  • Create a package on your project holders and then all view holder you put inside there, below is an example of holder:

  • Create an AbstractHolder with public void bindData(Data data) so then your adapter extends RecyclerView.Adapter<AbstractHolder>:

  • Create holders like below:

example Holder1.java

public class Holder1 extends AbstractHolder {

    // that's an example of views this would use
    @Bind(R.id.text) TextView text;
    @Bind(R.id.image) ImageView image;

    // constructor as normal:
    public Holder1(View itemView){
        super(itemView);
        ButterKnife.bind(this, itemView); // init the views
    }

    // call this from the adapter
    @Override public void bindData(Data data){
        text.setText(data.text);
        Picasso.with(itemView.getContext()).load(data.url).into(image);        
    }

    // here you create an instance of this holder,
    // this way the holder and the layout it's associated with goes together
    public static Holder1 create(ViewGroup parent){
        View root = LayoutInflater.from(parent.getContext()).inflate(R.layout.holder1, parent, false);
        return new Holder1(root);
    }

}
  • then your adapter code would be:

.

@Override public AbstractHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch(viewType){
            case TYPE_HOLDER_1: return Holder1.create(parent);
            case TYPE_HOLDER_2: return Holder2.create(parent);
            case TYPE_HOLDER_3: return Holder3.create(parent);
            ... carry on for all types   
        }
 }

@Override public void onBindViewHolder(AbstractHolder holder, int position) {
    Object data = getItem(position);
    holder.bindData(data);
}


// the get type would be similar to that:
@Override
public int getItemViewType(int position) {
    Object data = getItem(position);
    if( ... some condition...) return TYPE_HOLDER_1;
    else if( ... other condition...) return TYPE_HOLDER_2;
    else if( ... other condition...) return TYPE_HOLDER_3;
    ... etc ...
}

conclusion:

With this method your Adapter class is just a "distribution center" for the possible types and each type "knows" how to create itself and how to handle its data.

This makes your code easy to maintain and nicely organized.

like image 176
Budius Avatar answered Mar 23 '23 19:03

Budius