Nerd For Tech
Published in

Nerd For Tech

Nested RecyclerView In Android

A perfect guide to implement a recyclerview inside another recyclerview. Learn with MVVM

Photo by Author — Ghandruk, Nepal

💥 Hello, In this article we are going to implement a nested recyclerview. We will learn how exactly nested recyclerview are made in real-time projects.

We can use a RecyclerView inside another RecyclerView. We refer to this as nested RecyclerView. Here are some pictures of nested recyclerview applications.

Pictures of Nested Recyclerview Samples- eLibrary, Spotify, Netflix

Prerequisites

Why This Article? 🤔

Yeah, there are a lot of articles on this topic, but every article has its own way to represent data which is mainly static data. In this article we will build with API data.

Just Give me the Code,

Let's Get Started,

Step 1 — Setting up Model & API Data

An API that has a list of objects with the nested list of other objects. Take a look at the below API response. As we will integrate this public API into our application. Here, We have the Game Of Thrones API List which has a list of names of Houses and their nested Members list.

API Response
App Structure & UI

It’s important to understant data structure. I found many beginners developer were not able to understant API data structure which leads to bad development practice. So, Always understand model/data before you start your project.

Let’s SKIP our PEP talk and start coding Right! 👍

To generate KOTLIN model from JSON you can download this plugin (JSON To Kotlin Class) in Android Studio. And, For JAVA look (JSON To Java Class)

GameOfThrones.kt — Model

GameOfThrones Model

Now, Let's create API Service to get responses from the above API URL. By breaking down our URL into BASE_URL & EndPoints.

buildConfigField 'String', 'BASE_URL', "\"https://game-of-thrones-quotes.herokuapp.com/v1/\""

ApiEndPoints.kt

object ApiEndPoints {

const val GAME_OF_THRONES_URL = "houses"

}

ApiService.kt

interface ApiService {

@GET(ApiEndPoints.GAME_OF_THRONES_URL)
suspend fun getGameOfThronesData():Response<List<GameOfThrones>>
}

Now, Let's create our ViewModel to get this API Response

HomeViewModel.kt

Here, HomeRepository acts as a repository class to get our response & PreferencesHelper acts as a helper class to store data in SharedPreference. You can see the project repository to understand it more clearly.

Step 2— User Interface Setup (XML)

Here, We will need three layouts,

  1. Activity UI, For Toolbar & Parent RecyclerView
  2. A Layout row Item for Parent RecyclerView — which consists of title & child recyclerview.
  3. A Layout row Item for Child RecyclerView.
Three Layouts (1–2–3): Activity, Parent Item & Child Item

1. activity_home.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:fitsSystemWindows="true">

<include
android:id="@+id/title_layout"
layout="@layout/item_title_profile"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/parent_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingTop="10dp"
android:paddingBottom="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_layout" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.core.widget.NestedScrollView>

2. item_row_parent.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
app:cardCornerRadius="10dp"
app:cardElevation="1dp">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/content_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:includeFontPadding="false"
android:padding="10dp"
android:text="House of Stark"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/child_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/content_title" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

3. item_row_child.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_margin="15dp"
app:cardCornerRadius="30dp"
app:cardElevation="5dp"
android:layout_height="wrap_content">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:padding="20dp"
android:text="Jon Snow"
android:textColor="@color/colorPrimaryText"
app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

Step 3— Setting up Adapter Classes

Several different classes work together to build our dynamic list. Here we have two recyclerview, which means we need two adapters. You define the adapter by extending RecyclerView.Adapter. You define the view holder by extending RecyclerView.ViewHolder. The layout manager arranges the individual elements in your list.

Remember Parent-Child Concept. Parent Adapter holds Child Adapter.

A Parent-Child Illustration 👉

Let's start with the child members adapter, where we will plot a list of members.

ChildMembersAdapter.kt

Now, Let’s work on our ParentHouseAdapter, It is main/parent recyclerview adapter from which we will call our child adapter.

fun bind(result: GameOfThrones) {
itemView.content_title.text = result.name
val childMembersAdapter = ChildMembersAdapter(result.members)
itemView.child_recycler_view.layoutManager = LinearLayoutManager(itemView.context, LinearLayoutManager.HORIZONTAL,false)
itemView.child_recycler_view.adapter = childMembersAdapter

}

ParentHouseAdapter.kt

Final Step — Integrate Adapter In View

We have our adapter ready, In our Activity, we will call our adapter after we get a response from our API.

Finally, The Output we get,

Output of Application

We are done here. We can always change our UI view with respect to our API.

Thank you, Goodbye Take Care...

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store