Android Knowledge

RecyclerView in Android Studio using Kotlin – Easy 7 Steps Only!

recyclerview android studio kotlin

Table of Contents

RecyclerView

RecyclerView is a part of the view group that contains a single view that is recycled repeatedly to display the corresponding data.

We have item_layout as our single view which will display our data repeatedly in a recycler format.

In ArrayList, we will define all our data such as images and text then with the help of Adapter and ViewHolder we will display the data.

Download Drawables

Click Here

Step-by-Step Implementation

Step 1: Open Android Studio and Create New Project.

Choose Empty Activity, Name the Project, and Click Finish.

Step 2: colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="lavender">#8692f7</color>

</resources>

themes.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.RecyclerKotlin" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/lavender</item>
        <item name="colorPrimaryVariant">@color/lavender</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
</resources>

strings.xml

<resources>
    <string name="app_name">Android Basic Tutorials</string>

    <string name="listview">A list view is an adapter view that does not know the details, such as type and contents, of the views it contains.
        Instead list view requests views on demand from a ListAdapter as needed, such as to display new views as the
        user scrolls up or down. In order to display items in the list, call setAdapter(android.widget.ListAdapter)
        to associate an adapter with the list. For a simple example, see the discussion of filling an adapter view
        with text in the Layouts guide.</string>

    <string name="checkbox">Checkboxes allow the user to select one or more options from a set.
        Typically, you should present each checkbox option in a vertical list. To create each checkbox option,
        create a CheckBox in your layout. Because a set of checkbox options allows the user to select multiple items,
        each checkbox is managed separately and you must register a click listener for each one.</string>

    <string name="imageview">ImageView class is used to display any kind of image resource in the android application
        either it can be android.graphics.Bitmap or android.graphics.drawable.Drawable
        (it is a general abstraction for anything that can be drawn in Android).
        ImageView class or android.widget.ImageView inherits the android.view.View class which is the subclass
        of Kotlin. AnyClass.Application of ImageView is also in applying tints to an image in order to reuse a
        drawable resource and create overlays on background images. Moreover, ImageView is also used to control
        the size and movement of an image.</string>

    <string name="toggle">A toggle button allows the user to change a setting between two states.
        You can add a basic toggle button to your layout with the ToggleButton object.
        Android 4.0 (API level 14) introduces another kind of toggle button called a switch that provides
        a slider control, which you can add with a Switch object.</string>

    <string name="date">A thin wrapper around a millisecond value that allows JDBC to identify this as an SQL DATE
        value. A milliseconds value represents the number of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.
        To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance
        must be normalized by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.
        </string>

    <string name="rating">A RatingBar is an extension of SeekBar and ProgressBar that shows a rating in stars.
        The user can touch/drag or use arrow keys to set the rating when using the default size RatingBar.
        The smaller RatingBar style ( R.attr.ratingBarStyleSmall) and the larger indicator-only style
        (R.attr.ratingBarStyleIndicator) do not support user interaction and should only be used as indicators.
        When using a RatingBar that supports user interaction, placing widgets to the left or right of the
        RatingBar is discouraged.</string>

    <string name="time">A thin wrapper around the java.util.Date class that allows the JDBC API to identify
        this as an SQL TIME value. The Time class adds formatting and parsing operations to support the JDBC
        escape syntax for time values.
        The date components should be set to the "zero epoch" value of January 1, 1970 and should not be accessed.
        </string>

    <string name="textview">A TextView displays text to the user and optionally allows them to edit it.
        A TextView is a complete text editor, however the basic class is configured to not allow editing.
        </string>

    <string name="edit">A TextView displays text to the user and optionally allows them to edit it.
        A TextView is a complete text editor, however the basic class is configured to not allow editing.
        </string>

    <string name="camera">The Android framework includes support for various cameras and camera features available on devices, allowing you to capture pictures and videos in your applications.This document discusses a quick, simple approach to image and video capture and outlines an advanced approach for creating custom camera experiences for your users.</string>

</resources>

Step 3: activity_main.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:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.SearchView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:id="@+id/search"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:iconifiedByDefault="false"
        app:searchHintIcon="@null"
        app:queryHint="Search..."
        android:focusable="false"
        app:closeIcon="@drawable/ic_baseline_clear_24"
        app:searchIcon="@drawable/ic_baseline_search_24"
        android:background="@drawable/search_bkg"/>

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:id="@+id/recyclerView"
        android:layout_marginTop="12dp"
        app:layout_constraintTop_toBottomOf="@id/search"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

activity_detail.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:layout_height="match_parent"
    android:background="@color/white"
    tools:context=".DetailActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/detailTitle"
        android:layout_marginTop="24dp"
        android:text="Camera"
        android:textColor="@color/lavender"
        android:textSize="28sp"
        android:layout_marginStart="16dp"
        android:textAlignment="center"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="200dp"
        android:id="@+id/detailImage"
        android:layout_marginTop="20dp"
        android:scaleType="fitXY"
        android:src="@drawable/camera_detail"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/detailTitle"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/detailDesc"
        android:layout_marginTop="20dp"
        android:text="@string/camera"
        android:textColor="@color/lavender"
        android:textAlignment="viewStart"
        android:textSize="20sp"
        android:padding="12dp"
        android:layout_marginStart="16dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/detailImage"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Step 4: item_layout.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"
    app:cardCornerRadius="20dp"
    android:layout_marginHorizontal="10dp"
    android:layout_marginVertical="10dp"
    app:cardElevation="8dp">

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

        <ImageView
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:id="@+id/image"
            android:layout_marginStart="20dp"
            android:padding="8dp"
            android:adjustViewBounds="true"
            android:scaleType="fitXY"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:src="@drawable/ic_list" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/title"
            android:textColor="@color/black"
            android:textSize="16sp"
            android:text="Title"
            android:layout_marginStart="20dp"
            app:layout_constraintStart_toEndOf="@id/image"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

Step 5: DataClass.kt

package com.example.recyclerviewkotlin

import android.os.Parcel
import android.os.Parcelable

data class DataClass(var dataImage:Int, var dataTitle:String, var dataDesc: String, var dataDetailImage: Int): Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readInt(),
        parcel.readString()!!,
        parcel.readString()!!,
        parcel.readInt()
    ) {
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(dataImage)
        parcel.writeString(dataTitle)
        parcel.writeString(dataDesc)
        parcel.writeInt(dataDetailImage)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<DataClass> {
        override fun createFromParcel(parcel: Parcel): DataClass {
            return DataClass(parcel)
        }

        override fun newArray(size: Int): Array<DataClass?> {
            return arrayOfNulls(size)
        }
    }
}

Step 6: AdapterClass.kt

package com.example.recyclerviewkotlin

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class AdapterClass(private val dataList: ArrayList<DataClass>): RecyclerView.Adapter<AdapterClass.ViewHolderClass>() {

    var onItemClick: ((DataClass) -> Unit)? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderClass {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
        return ViewHolderClass(itemView)
    }

    override fun onBindViewHolder(holder: ViewHolderClass, position: Int) {
        val currentItem = dataList[position]
        holder.rvImage.setImageResource(currentItem.dataImage)
        holder.rvTitle.text = currentItem.dataTitle

        holder.itemView.setOnClickListener{
            onItemClick?.invoke(currentItem)
        }
    }

    override fun getItemCount(): Int {
        return dataList.size
    }

    class ViewHolderClass(itemView: View): RecyclerView.ViewHolder(itemView) {
        val rvImage:ImageView = itemView.findViewById(R.id.image)
        val rvTitle:TextView = itemView.findViewById(R.id.title)
    }
}

Step 7: MainActivity.kt

package com.example.recyclerviewkotlin

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.util.*
import kotlin.collections.ArrayList

class MainActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var dataList: ArrayList<DataClass>
    lateinit var imageList:Array<Int>
    lateinit var titleList:Array<String>
    lateinit var descList: Array<String>
    lateinit var detailImageList: Array<Int>
    private lateinit var myAdapter: AdapterClass
    private lateinit var searchView: SearchView
    private lateinit var searchList: ArrayList<DataClass>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        imageList = arrayOf(
            R.drawable.ic_list,
            R.drawable.ic_checkbox,
            R.drawable.ic_image,
            R.drawable.ic_toggle,
            R.drawable.ic_date,
            R.drawable.ic_rating,
            R.drawable.ic_time,
            R.drawable.ic_text,
            R.drawable.ic_edit,
            R.drawable.ic_camera)

        titleList = arrayOf(
            "ListView",
            "CheckBox",
            "ImageView",
            "Toggle Switch",
            "Date Picker",
            "Rating Bar",
            "Time Picker",
            "TextView",
            "EditText",
            "Camera")

        descList = arrayOf(
            getString(R.string.listview),
            getString(R.string.checkbox),
            getString(R.string.imageview),
            getString(R.string.toggle),
            getString(R.string.date),
            getString(R.string.rating),
            getString(R.string.time),
            getString(R.string.textview),
            getString(R.string.edit),
            getString(R.string.camera))

        detailImageList = arrayOf(
            R.drawable.list_detail,
            R.drawable.check_detail,
            R.drawable.image_detail,
            R.drawable.toggle_detail,
            R.drawable.date_detail,
            R.drawable.rating_detail,
            R.drawable.time_detail,
            R.drawable.text_detail,
            R.drawable.edit_detail,
            R.drawable.camera_detail)

        recyclerView = findViewById(R.id.recyclerView)
        searchView = findViewById(R.id.search)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.setHasFixedSize(true)

        dataList = arrayListOf<DataClass>()
        searchList = arrayListOf<DataClass>()
        getData()

        searchView.clearFocus()
        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
            override fun onQueryTextSubmit(query: String?): Boolean {
                searchView.clearFocus()
                return true
            }

            override fun onQueryTextChange(newText: String?): Boolean {
                searchList.clear()
                val searchText = newText!!.toLowerCase(Locale.getDefault())
                if (searchText.isNotEmpty()){
                    dataList.forEach{
                        if (it.dataTitle.toLowerCase(Locale.getDefault()).contains(searchText)) {
                            searchList.add(it)
                        }
                    }
                    recyclerView.adapter!!.notifyDataSetChanged()
                } else {
                    searchList.clear()
                    searchList.addAll(dataList)
                    recyclerView.adapter!!.notifyDataSetChanged()
                }
                return false
            }

        })

        myAdapter = AdapterClass(searchList)
        recyclerView.adapter = myAdapter

        myAdapter.onItemClick = {
            val intent = Intent(this, DetailActivity::class.java)
            intent.putExtra("android", it)
            startActivity(intent)
        }

    }

    private fun getData(){
        for (i in imageList.indices){
            val dataClass = DataClass(imageList[i], titleList[i], descList[i], detailImageList[i])
            dataList.add(dataClass)
        }
        searchList.addAll(dataList)
        recyclerView.adapter = AdapterClass(searchList)
    }
}

DetailActivity.kt

package com.example.recyclerviewkotlin

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.ContactsContract.Data
import android.widget.ImageView
import android.widget.TextView

class DetailActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_detail)

        val getData = intent.getParcelableExtra<DataClass>("android")
        if (getData != null) {
            val detailTitle: TextView = findViewById(R.id.detailTitle)
            val detailDesc: TextView = findViewById(R.id.detailDesc)
            val detailImage: ImageView = findViewById(R.id.detailImage)

            detailTitle.text = getData.dataTitle
            detailDesc.text = getData.dataDesc
            detailImage.setImageResource(getData.dataDetailImage)
        }
    }
}

Output

AK Bonus Points

If you have any queries or errors, please feel free to comment below 🙂

For detailed steps, watch our youtube video: RecyclerView in Android Studio using Kotlin

Watch Retrieve Firebase Data in Profile YT Video: How to Retrieve Data from Firebase Database and Display in Profile Activity – Android Studio

Check our similar post here: Login and Signup using Firebase Authentication in Android Studio