This is a simple tutorial to develop a scrolling horizontal RecyclerView inside a vertical RecyclerView in Android.
First, we will create the main layout that shows the vertical RecyclerView:
courses_fragment.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:paddingLeft="15dp" android:paddingRight="15dp"> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id=“@+id/vertical_courses_list" android:visibility="gone"/> </RelativeLayout>
It’s a simple relative layout with a RecyclerView in it.
Now let’s create the layout for each item of the vertical RecyclerView:
courses_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="15dp" android:layout_marginBottom="15dp"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_alignParentLeft="true" android:layout_centerVertical="true"> <TextView android:id="@+id/course_item_name_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/RegularTextStyle"/> <android.support.v7.widget.RecyclerView android:id="@+id/horizontal_list" android:layout_width="match_parent" android:layout_marginTop="5dp" android:layout_height="30dp" android:visibility="visible"/> </LinearLayout> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:src="@drawable/ic_play_circle_outline_white_24dp" android:tint="@color/colorAccent"/> </RelativeLayout>
We’ve made a Relative layout with a TextView that displays a Name, an Arrow to the right, and an inside RecyclerView below the Name.
Note: it is important that the inner RecyclerView has layout_height assigned, it won’t work with match_parent or wrap_content.
The same way we created a layout for each item of the main RecyclerView, we will have to create a new layout for each item of the inner horizontal RecyclerView:
courses_horizontal_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginRight="3dp"> <TextView android:id="@+id/horizontal_item_text" android:textColor="@color/white" android:layout_width="match_parent" android:padding="5dp" android:layout_height="wrap_content" android:gravity="center_vertical"/> </LinearLayout>
Good! We are done with xml files. Now we have to create the adapters for each RecyclerView. Let’s start with inner Horizontal RecyclerView adapter:
HorizontalRVAdapter
public class HorizontalRVAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List<String> mDataList; private int mRowIndex = -1; public HorizontalRVAdapter() { } public void setData(List<String> data) { if (mDataList != data) { mDataList = data; notifyDataSetChanged(); } } public void setRowIndex(int index) { mRowIndex = index; } private class ItemViewHolder extends RecyclerView.ViewHolder { private TextView text; public ItemViewHolder(View itemView) { super(itemView); text = (TextView) itemView.findViewById(R.id.horizontal_item_text); } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Context context = parent.getContext(); View itemView = LayoutInflater.from(context).inflate(R.layout.courses_horizontal_item, parent, false); ItemViewHolder holder = new ItemViewHolder(itemView); return holder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder rawHolder, int position) { ItemViewHolder holder = (ItemViewHolder) rawHolder; holder.text.setText(mDataList.get(position)); holder.itemView.setTag(position); } @Override public int getItemCount() { return mDataList.size(); } }
Here we inflate the layout for each item of the horizontal RecyclerView and set data to each view. In this case we only have a TextView which is filled with a String from List<String>, but views and lists can be customized and be more complex according to each need.
Now let’s wrap it all together in the main RecyclerView adapter:
CourseRVAdapter
public class CourseRVAdapter extends RecyclerView.Adapter<CourseRVAdapter.SimpleViewHolder> { private final Context mContext; private static List<Nugget> mData; private static RecyclerView horizontalList; public static class SimpleViewHolder extends RecyclerView.ViewHolder { public final TextView title; private HorizontalRVAdapter horizontalAdapter; public SimpleViewHolder(View view) { super(view); Context context = itemView.getContext(); title = (TextView) view.findViewById(R.id.course_item_name_tv); horizontalList = (RecyclerView) itemView.findViewById(R.id.horizontal_list); horizontalList.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); horizontalAdapter = new HorizontalRVAdapter(); horizontalList.setAdapter(horizontalAdapter); } } public CourseRVAdapter(Context context, List<Nugget> data) { mContext = context; if (data != null) mData = new ArrayList<>(data); else mData = new ArrayList<>(); } public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { final View view = LayoutInflater.from(mContext).inflate(R.layout.courses_item, parent, false); return new SimpleViewHolder(view); } @Override public void onBindViewHolder(SimpleViewHolder holder, final int position) { holder.title.setText(mData.get(position).getTitle()); holder.horizontalAdapter.setData(mData.get(position).getTags()); // List of Strings holder.horizontalAdapter.setRowIndex(position); } @Override public int getItemCount() { return mData.size(); } }
And finally, we set the main RecyclerView adapter in our Activity/Fragment:
private CourseRVAdapter adapter; … // Setting RecyclerView coursesRecyclerView.setHasFixedSize(true); LinearLayoutManager llm = new LinearLayoutManager(getActivity()); coursesRecyclerView.setLayoutManager(llm); // nuggetsList is an ArrayList of Custom Objects, in this case Nugget.class adapter = new CourseRVAdapter(getActivity(), nuggetsList); coursesRecyclerView.setAdapter(adapter);