How to Create Expandable RecyclerView items in Android using Kotlin? - GeeksforGeeks

24 Mar, 2021

RecyclerView is a ViewGroup added to the android studio as a successor of the GridView and ListView. It is an improvement on both of them and can be found in the latest v-7 support packages. It has been created to make possible construction of any lists with XML layouts as an item that can be customized vastly while improving the efficiency of ListViews and GridViews. This improvement is achieved by recycling the views which are out of the visibility of the user. For example, if a user scrolled down to a position where items 4 and 5 are visible; items 1, 2, and 3 would be cleared from the memory to reduce memory consumption. In this article, we will explain how to create Expandable Recycler View items in android. Below is the sample video to show what we are going to build. Note that we are going to implement this project using the Kotlin language. 
Step 1: Create a new project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.
Step 2: Add view binding dependency
Go to build.gradle(app) and the following dependency inside the android tag and click sync now.
 buildFeatures {
      viewBinding true
  }
Step 3: Working with the activity_main.xml
Go to the activity_main.xml file and refer to the following code. Below is the code for the activity_main.xml file. It has only a single Recycler view which we will use to show our data.
XML
 

 
 










<?xml version="1.0" encoding="utf-8"?> 
<androidx.constraintlayout.widget.ConstraintLayout 
    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:background="#F5F8FD"
    android:layout_height="match_parent"
    tools:context=".MainActivity"> 
  
    <!--Add recycler view to main activity-->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@layout/single_item"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> 
  
</androidx.constraintlayout.widget.ConstraintLayout>






Step 4: Create a new layout file and name it as single_item.xml file
Go to the single_item.xml file and refer to the following code. Below is the code for the single_item.xml file. It is the single item layout that we will use in RecyclerView.
XML
 

 
 










<?xml version="1.0" encoding="utf-8"?> 
<com.google.android.material.card.MaterialCardView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="5dp"
    android:layout_marginEnd="5dp"
    android:layout_marginBottom="10dp"> 
  
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"> 
        
        <!--Text view for showing the language name-->
        <TextView
            android:id="@+id/tv_lang_name"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginStart="20dp"
            android:layout_marginTop="10dp"
            android:text="Language"
            android:textColor="@color/black"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" /> 
        
        <!--This is the layout "expanded_view" we will  
            hide initially and show as expanded 
            layout when user clicks on any of the item-->
        <RelativeLayout
            android:id="@+id/expanded_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tv_lang_name"> 
            
            <!--It has a text view which we will use in our case as 
                a description text for the languages-->
            <TextView
                android:id="@+id/tv_description"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:text="Description Text"
                android:textSize="18sp" /> 
        </RelativeLayout> 
        
    </androidx.constraintlayout.widget.ConstraintLayout> 
    
</com.google.android.material.card.MaterialCardView>






Step 5: Create a new model class
Create a new class Language.kt we will use data of custom generic “Language” to pass in the list that will be shown in RecyclerView.
Kotlin
 

 
 










// this is the Language model class 
class Language( 
    val name : String ="", 
    val description : String= "", 
    var expand : Boolean = false
)






Step 6: Working with adapter class
Create a new class RvAdapter.kt this will act as an Adapter class for the recycler view. The logic behind the expandable recycler view is that initially, we will make the visibility of layout with id “expanded_view” of “single_item.xml” to GONE and once the user clicks on any item of recycler view we will make its visibility VISIBLE. Comments are added before the code for better understanding.
Kotlin
 

 
 










import android.view.LayoutInflater 
import android.view.View 
import android.view.ViewGroup 
import androidx.recyclerview.widget.RecyclerView 
import com.geeksforgeeks.rvadapterviewbinding.databinding.SingleItemBinding 
  
class RvAdapter( 
    private var languageList: List<Language> 
) : RecyclerView.Adapter<RvAdapter.ViewHolder>() { 
  
    // create an inner class with name ViewHolder 
    // It takes a view argument, in which pass the generated class of single_item.xml 
    // ie SingleItemBinding and in the RecyclerView.ViewHolder(binding.root) pass it like this 
    inner class ViewHolder(val binding: SingleItemBinding) : RecyclerView.ViewHolder(binding.root) 
  
    // inside the onCreateViewHolder inflate the view of SingleItemBinding 
    // and return new ViewHolder object containing this layout 
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 
        val binding = SingleItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) 
        return ViewHolder(binding) 
    } 
  
    // bind the items with each item of the list languageList which than will be 
    // shown in recycler view 
    // to keep it simple we are not setting any image data to view 
    override fun onBindViewHolder(holder: ViewHolder, position: Int) { 
        with(holder){ 
            with(languageList[position]){ 
                // set name of the language from the list 
                binding.tvLangName.text = this.name 
                // set description to the text 
                // since this is inside "expandedView" its visibility will be gone initially 
                // after click on the item we will make the visibility of the "expandedView" visible 
                // which will also make the visibility of desc also visible 
                binding.tvDescription.text = this.description 
                // check if boolean property "extend" is true or false 
                // if it is true make the "extendedView" Visible 
                binding.expandedView.visibility = if (this.expand) View.VISIBLE else View.GONE 
                // on Click of the item take parent card view in our case 
                // revert the boolean "expand" 
                binding.cardLayout.setOnClickListener { 
                    this.expand = !this.expand 
                    notifyDataSetChanged() 
                } 
            } 
        } 
    } 
    // return the size of languageList 
    override fun getItemCount(): Int { 
        return languageList.size 
    } 
}






Step 7: Working with MainActivity.kt
Go to the MainActivity.kt file and refer to the following code. Below is the code for the MainActivity.kt file. Comments are added inside the code to understand the code in more detail.
Kotlin
 

 
 










import androidx.appcompat.app.AppCompatActivity 
import android.os.Bundle 
import androidx.recyclerview.widget.LinearLayoutManager 
import com.geeksforgeeks.rvadapterviewbinding.databinding.ActivityMainBinding 
  
class MainActivity : AppCompatActivity() { 
  
    // view binding for the activity 
    private var _binding: ActivityMainBinding? = null
    private val binding get() = _binding!! 
  
    // get reference to the adapter class 
    private var languageList = ArrayList<Language>() 
    private lateinit var rvAdapter: RvAdapter 
  
    override fun onCreate(savedInstanceState: Bundle?) { 
        super.onCreate(savedInstanceState) 
        _binding = ActivityMainBinding.inflate(layoutInflater) 
        setContentView(binding.root) 
  
        // define layout manager for the Recycler view 
        binding.rvList.layoutManager = LinearLayoutManager(this) 
          
        // attach adapter to the recycler view 
        rvAdapter = RvAdapter(languageList) 
        binding.rvList.adapter = rvAdapter 
  
        // create new objects 
        // add some row data 
        val language1 = Language( 
            "Java", 
            "Java is an Object Oriented Programming language." + 
                    " Java is used in all kind of applications like Mobile Applications (Android is Java based), " + 
                    "desktop applications, web applications, client server applications, enterprise applications and many more. ", 
            false
        ) 
        val language2 = Language( 
            "Kotlin", 
            "Kotlin is a statically typed, general-purpose programming language" + 
                    " developed by JetBrains, that has built world-class IDEs like IntelliJ IDEA, PhpStorm, Appcode, etc.", 
            false
        ) 
        val language3 = Language( 
            "Python", 
            "Python is a high-level, general-purpose and a very popular programming language." + 
                    " Python programming language (latest Python 3) is being used in web development, Machine Learning applications, " + 
                    "along with all cutting edge technology in Software Industry.", 
            false
        ) 
        val language4 = Language( 
            "CPP", 
            "C++ is a general purpose programming language and widely used now a days for " + 
                    "competitive programming. It has imperative, object-oriented and generic programming features. ", 
            false
        ) 
  
        // add items to list 
        languageList.add(language1) 
        languageList.add(language2) 
        languageList.add(language3) 
        languageList.add(language4) 
  
        rvAdapter.notifyDataSetChanged() 
  
    } 
  
    // on destroy of view make the binding reference to null 
    override fun onDestroy() { 
        super.onDestroy() 
        _binding = null
    } 
}






Output:
Github Repo here.

Kotlin Android


Android


Kotlin

Writing code in comment? 
                                    Please use ide.geeksforgeeks.org, 
                                    generate link and share the link here.
                                
Flutter - Custom Bottom Navigation Bar
How to Read Data from SQLite Database in Android?
Retrofit with Kotlin Coroutine in Android
Android Listview in Java with Example
How to Change the Background Color After Clicking the Button in Android?
Android UI Layouts
Kotlin Array
Retrofit with Kotlin Coroutine in Android
Kotlin Setters and Getters
MVP (Model View Presenter) Architecture Pattern in Android with Example