4

I have two different types of objects (ex: User and Student) both having different properties.

User: Title, description;
Student: Title, description, USN;

Is there a way using which I can display two users first and then students on the recycler view using same adapter? How do I display it even if it's two adapters. I don't want two recycler views.

Please note that the example given is very simple. The change is not just in UI. If the change is just in UI, then getItemViewType() can be used but here the change is in the model itself.

List<Student> and List<User>

How do we set both the lists to same adapter?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Varun A M
  • 1,103
  • 2
  • 14
  • 29
  • what are the properties of Student. Add code Dear so that other can help you – Jawad Zeb Sep 10 '18 at 06:37
  • Use data binding for achieve this. – Hemant Parmar Sep 10 '18 at 06:39
  • You can use Marker interface here. – Pankaj Kant Patel Sep 10 '18 at 06:40
  • have you tried using expendable recycler view ? – Umair Sep 10 '18 at 06:42
  • 2
    Possible duplicate of [How to create RecyclerView with multiple view type?](https://stackoverflow.com/questions/26245139/how-to-create-recyclerview-with-multiple-view-type) – Manohar Sep 10 '18 at 06:51
  • There are really good examples of what you're trying to do with a good explanation. Even dating back to 2010: http://android.amberfog.com/?p=296, https://medium.com/@sreekumar_av/recyclerview-with-multiple-type-t-of-views-and-how-to-bind-without-casting-5f453e4436aa, https://guides.codepath.com/android/Implementing-a-Heterogenous-ListView – Variag Sep 14 '18 at 08:03

3 Answers3

5

You have to use the override method "getItemViewType(position)".

Then just return the ViewHolder as per the ViewType like this,

  @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder viewHolder = null;
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());

    switch (viewType) {
        case ITEM:
            View v1 = inflater.inflate(R.layout.item_student, parent, false);
            viewHolder = new UserVH(v1);
            break;
        case LOADING:
            View v2 = inflater.inflate(R.layout.item_user, parent, false);
            viewHolder = new StudentVH(v2);
            break;
    }
    return viewHolder;
}

Edit:

 public class StudentVH extends RecyclerView.ViewHolder {
    //Declare student views

    public ViewHolder(View v) {
        super(v);
        //Inialize student views
    }
}

 public class UserVH extends RecyclerView.ViewHolder {
    //Declare user views

    public ViewHolder(View v) {
        super(v);
        //Inialize user views
    }
}

Second Edit:

Your Adapter should be like this,

public class ClGAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<UserBean> userBeans;
private List<StudentBean> studentBeans;
private UserBean userBeanItem;
private StudentBean studentBeanItem;
private int size = 0;


public ClGAdapter(Context context, List<UserBean> userBeans, List<StudentBean> studentBeans) {
    this.context = context;
    this.userBeans = userBeans;
    this.studentBeans = studentBeans;
    this.size = userBeans.size() + studentBeans.size();
}


@Override
public int getItemViewType(int position) {

    if (position > (userBeans.size() - 1)) {
        return 2;//TYPE_STUDENT
    } else {
        return 1; //TYPE_USER
    }
}

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {

    int viewType = holder.getItemViewType();

    userBeanItem = userBeans.get(position);
    studentBeanItem = studentBeans.get(position);
    switch (viewType) {
        case 1:
            ((UserHolder) holder).mUserName.setText(userBeanItem.getUserName());
            break;
        case 2:
            ((StudentHolder) holder).mStudentName.setText(studentBeanItem.getStudentName());
            break;
        default:
            break;
    }

}

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

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    int layout = 0;
    RecyclerView.ViewHolder viewHolder;
    switch (viewType) {
        case 1: 
            layout = R.layout.user_card;
            View userView = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
            viewHolder = new UserHolder(userView);
            break;
        case 2:
            layout = R.layout.student_card;
            View studentView = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
            viewHolder = new StudentHolder(studentView);

            break;
        default:
            viewHolder = null;
            break;
    }
    return viewHolder;
}

public class UserHolder extends RecyclerView.ViewHolder {
    private TextView mUserName;

    public UserHolder(View v) {
        super(v);
        mUserName = v.findViewById(R.id.user_name);
    }
}

public class StudentHolder extends RecyclerView.ViewHolder {
    private TextView mStudentName;

    public StudentHolder(View v) {
        super(v);
        mStudentName = v.findViewById(R.id.student_name);
    }
}
}
Sana
  • 456
  • 3
  • 9
  • The change isn't just in UI. It's with the model itself. How to set List and List to same adapter? – Varun A M Sep 13 '18 at 07:31
  • You have to create two different model for both Student and User.I have mentioned in my answer.Only one RecyclerView is enough.Thank you – Sana Sep 13 '18 at 07:33
  • How do you set both lists to same adapter? The code you have given is about ViewHolder and not about different models – Varun A M Sep 13 '18 at 07:39
  • Check I have editted my answer and wait I will be providing the code that how to fetch the list to different models in same adapter as well as same RecylclerView – Sana Sep 13 '18 at 07:41
  • Hi, thanks for the edit. I can see that you are taking only one list in constructor where I have two lists. That's where is my problem is :( – Varun A M Sep 13 '18 at 08:03
  • I have edited my code.Please cheeck.It will fit your need.And if you feel it is helpful please mark it as accepted.Thank you – Sana Sep 13 '18 at 08:38
3

I will give you my implementation, hope will help:

public class UserStudentAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static final int USER_VIEW_TYPE = 0;
    private static final int STUDENT_VIEW_TYPE = 1;

    private List<User> mUserData;
    private List<Student> mStudentData;

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        switch (viewType) {
            case HEADER_VIEW_TYPE:
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_definition_header, parent, false);
                return new HeaderViewHolder(view);
            case CONTENT_VIEW_TYPE:
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_index, parent, false);
                return new ItemViewHolder(view);
            default:
                return null;
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        switch (getItemViewType(position)) {
            case USER_VIEW_TYPE:
                //Show User data
                break;
            case STUDENT_VIEW_TYPE:
                //Show Student data
                break;
            default:
                break;
        }
    }

    @Override
    public int getItemCount() {
        return mUserData.size() + mStudentData.size();
    }

    @Override
    public int getItemViewType(int position) {
        return (position % 2 == 0) ? STUDENT_VIEW_TYPE : USER_VIEW_TYPE;
    }

}
MrVasilev
  • 1,503
  • 2
  • 17
  • 34
  • The change isn't just in UI. It's with the model itself. How to set List and List to same adapter? – Varun A M Sep 13 '18 at 07:31
  • 3
    You have two choices. The first one is this which I present in my example, have two different Lists in the Adapter, one for users List mUserData and one for students List mStudentData. The other option is if your User and Student classes have common parent, for example Person and you can have only one list in your adapter List mData. Depend on that which option you will choose your Adapter has to have different methods to update the data, for example public void updateData(List data) and call notifyDataSetChanged() – MrVasilev Sep 13 '18 at 07:51
  • @VarunAM is my answer and comment help you? :) – MrVasilev Sep 13 '18 at 09:15
0

just use viewType, return different viewType and bind different data in onBindViewHolder

HaKu
  • 41
  • 8