Kiwiapps Ltd. Kiwiapps Ltd. - 2 months ago 11
Android Question

Inflate two types of .XML in RecyclerView

I have gone under a lot of frustration all because of this one issue I'm having: how do I inflate different .XML files for different objects in a RecyclerView? I have done as much as I can do, such as making a ListItemType object:

public class ListItemType {
public static int NOTE_VIEW = 0;
public static int CATEGORY_VIEW = 1;
}


And a ListViewItem object:

public class ListViewItem {
private int mType;
private Object mObject;

public ListViewItem(int type, Object object) {
mType = type;
mObject = object;
}

public int getType() {
return mType;
}

public void setType(int type) {
mType = type;
}

public Object getObject() {
return mObject;
}

public void setObject(Object object) {
mObject = object;
}
}


I'm clueless as to where I go from here.

Answer

RecyclerView Implement

First of all you have to add/create to/your Model type that indicates the your Model type and to know which layout to inflate:

MyModel.java

public class MyModel {
    public enum ModelTypes {
        TYPE_1,
        TYPE_2
    }
    // your model members ^^^

    ModelTypes type;
}

Now you have to create your ViewHolder, I suggest to create a parent ViewHolder class and extends your model types with sub classes.

MyHolder.java

public class MyHolder extends RecyclerView.ViewHolder {

    // must have the ViewHolder default constructor
    public MyHolder(View itemView) {
        super(itemView);
    }

    public static MyHolder inflateViewByType(MyModel.ModelTypes type, 
                                            LayoutInflater layoutInflater, ViewGroup parent) {
        View view;
        switch (type) {
            case TYPE_1:
                view = layoutInflater.inflate(R.layout.layout_type_1, parent, false);
                return new MyHolderType1(view);
            break;
            case TYPE_2:
                view = layoutInflater.inflate(R.layout.layout_type_2, parent, false);
                return new MyHolderType2(view);
            break;
        }
        // Model type not supported
        return null;
    }
}

Create your ViewHolder types, in my example i have only two types.

MyHolderType1.java

public class MyHolderType1 extends MyHolder {

    // layout members

    public MyHolderType1(View itemView) {
        super(itemView);
        // init your layout members by for layout_type_1 by itemView.findViewById(...)
    }
}

MyHolderType2.java

public class MyHolderType2 extends MyHolder {

    // layout members

    public MyHolderType2(View itemView) {
        super(itemView);
        // init your layout members by for layout_type_2 by itemView.findViewById(...)
    }
}

Until now you only create the ViewHolder types to implement the RecyclerView. RecyclerView must have an Adapter that extends the default RecyclerView.Adapter, to do this we have to create a new class and extends the RecyclerView.Adapter with our ViewHolder.

MyRecyclerViewAdapter.java

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyHolder> {

    private List<MyModel> mData;

    public MyRecyclerViewAdapter(@NonNull List<MyModel> data) {
        mData = data;
    }

    @Override
    public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        MyModel.ModelTypes type = MyModel.ModelTypes.values()[viewType];
        return MyHolder.inflateViewByType(type, layoutInflater, parent);
    }

    @Override
    public void onBindViewHolder(MyHolder holder, int position) {

        MyModel model = mData.get(position);
        switch (model.type) {
            case TYPE_1:
                setupViewType1((MyHolderType1) holder, model);
                break;
            case TYPE_2:
                setupViewType2((MyHolderType2) holder, model);
                break;
        }
    }

    // to update the adapter data without reinitialize it
    public void updateData(@NonNull List<MyModel> newData) {
        mData = newData;
        notifyDataSetChanged();
    }

    private void setupViewType1(MyHolderType1 holder, MyModel model) {

        // do what you want with your views in layout_type_1
    }

    private void setupViewType2(MyHolderType2 holder, MyModel model) {

        // do what you want with your views in layout_type_2
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    @Override
    public int getItemViewType(int position) {
        return mData.get(position).type.ordinal();
    }
}

Keep going, we almost done. Now we have to initialize the RecyclerView in our activity, and set the an instance of MyRecyclerViewAdapter to it. To this we have find out RecyclerView in and xml by calling findViewById(...), and then set the LayoutManager to the RecyclerView, after all we set the adapter with our data.

MyActivity.java

public class MyActivity extends Activity{

    // ....

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_layout);


        // init your views
        RecyclerView recyclerView = findViewById(R.id.recycler_view);


        // here you can pull or generate your recycler view list data
        List<MyModel> data = getData();
        MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(data);


        // set layout manager to the recycler view (Required)
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, 
                                                        LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(linearLayoutManager);

        // set the adapter to the recycler view (Required)
        recyclerView.setAdapter(adapter);
    }

    // ....
}
Comments