How to add a scrollbar with a draggable thumb and value label to a RecyclerView

RecyclerView widgets are a great way of displaying content in an Android app; however, they can become cumbersome as the content size increases. For example, long lists of content can require a lot of scrolling. While the RecyclerView's fastScrollEnabled property offers a partial solution by adding a fast-scroller to the RecyclerView, this feature also has issues. First, you must create a thumb and track for the fast-scroller, which is extra work. Second, the fast-scroller thumb can shrink to a minuscule size when a large amount of content is loaded. The shrinking scrollbar issue was raised with Google several years ago; however, at the time of writing a fix has yet to be released.

To provide a better solution for RecyclerView navigation, we here at Coders' Guidebook created a library that allows you to add a fast-scroller, thumb and value label to your RecyclerView widgets. The library is Kotlin-based, easy to use, customisable and supports Android SDKs 29 to 33. In this tutorial, you will learn how to add the fast-scroller to your app and explore its features. If you're interested, you can find the source code and an example app that uses the scrollbar on our GitHub. A separate tutorial that explains how the scrollbar was built is available here.

recyclerview-scrollbar-fast-scroller-value-label.gif

Adding the scrollbar library to your Android Studio project

Let's start by adding the scrollbar library to an Android Studio project. The simplest way to do this by adding the Maven dependency for the library to your module-level build.gradle file; however, we will also cover how to add the library manually.

Importing the scrollbar library from Maven

The recyclerview-fastscroller-with-value-label library is published in Maven Central, so can easily be imported into your Android Studio project via Gradle. To do this, open the project's module-level build.gradle file.

module-level-build-gradle.png

Next, add the following line of code to the dependencies element to import the scrollbar library.

implementation 'com.codersguidebook:recyclerview-fastscroller-with-value-label:1.0'

Remember to resync your project when prompted and the library should be ready to use.

resync-gradle.png

Manually importing the scrollbar library as an .aar file

The simplest way to import the scrollbar library is via Maven; however, you can also add the library manually. To do this, download the attached recyclerviewfastscroller-release.aar file (.aar files are how Android libraries are packaged). Next, in Android Studio, switch to the Project view of the project's directory structure.

project-directory-structure-android-studio.png

Drag and drop the downloaded recyclerviewfastscroller-release.aar file to the libs folder of the application module you wish to add the scrollbar library to (often called app).

add-library-libs-directory.png

Next, open the module-level build.gradle file and locate the dependencies element. Add the following code to the list of dependencies to import the scrollbar library into your project:

implementation files('libs/recyclerviewfastscroller-release.aar')

Once that's done, resync your project as prompted and the library should be ready to use!

resync-gradle.png

Applying the scrollbar to a RecyclerView widget

To apply the scrollbar to a RecyclerView widget, simply locate the layout file that contains the RecyclerView and add a RecyclerViewScrollbar element as shown below:

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

<com.codersguidebook.recyclerviewfastscroller.RecyclerViewScrollbar
    android:id="@+id/scrollbar"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    app:layout_constraintEnd_toEndOf="@id/recyclerView" />

Some key points to note about the above code. First, you should assign the scrollbar an ID (e.g. scrollbar). The ID will allow us to refer to the scrollbar elsewhere in the code. Second, for best performance, the width of the scrollbar should be set to wrap_content, and the height of the scrollbar should equal the RecyclerView. In this case, both the RecyclerView and scrollbar have a height of match_parent, which means they will occupy the maximum possible height within the layout. Finally, the scrollbar should be constrained to the right-hand side of the RecyclerView, so that the scrollbar appears in the appropriate position relative to the RecyclerView's content. Additional customisable properties for the scrollbar will be covered in a later section.

Moving on, we now need to link the RecyclerView and scrollbar so that they can coordinate changes in the scroll position. To do this, open the Kotlin file that is responsible for the layout containing the RecyclerView and scrollbar. Often, this Kotlin file will be for a fragment or an activity. Next, add code similar to the following to the area of the Kotlin file where you initialise the layout's components (e.g. the onViewCreated stage of the fragment lifecycle):

binding.scrollbar.recyclerView = binding.recyclerView
binding.recyclerView.addOnScrollListener(RecyclerViewScrollbar.OnScrollListener(binding.scrollbar))

The above code assumes you use view binding to interact with the layout's components. It also assumes that the RecyclerView and RecyclerViewScrollbar widgets have IDs of recyclerView and scrollbar, respectively. The first line of code supplies a reference to the RecyclerView widget to the scrollbar, while the second line of code registers an onScrollListener to the RecyclerView. The scrollbar will automatically monitor the size of the content loaded into the RecyclerView and adjust the height of the scrollbar thumb accordingly; however, the thumb will always have a minimum height to prevent it from becoming too small when the length of the RecyclerView's content is large. By default, the minimum thumb height will be 100dp, although you can set a different minimum thumb height via the scrollbar's thumbMinHeight property. The onScrollListener will notify the scrollbar whenever the RecyclerView scroll position changes so the thumb will move accordingly.

It is possible to override the OnScrollListener provided by the scrollbar. For example, you may have additional actions to perform during scroll events. In which case, use the below code to create a customisable OnScrollListener instance and add any extra code to its onScrolled method. The onScrolled method must retain a call to super.onScrolled(recyclerView, dx, dy), so the scrollbar can continue to function as normal.

binding.recyclerView.addOnScrollListener(object: RecyclerViewScrollbar
    .OnScrollListener(binding.scrollRecyclerView.scrollbar) {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)

            // Add extra code to handle scroll events here
        }
    })

Adding a value label to the scrollbar

The scrollbar supports a customisable value label. For example, if you have a RecyclerView that displays content sorted in alphabetical order, then the scrollbar can display a value label featuring the first letter of the item associated with the given scroll position. To add a value label to the scrollbar, open the Kotlin class file for the adapter which manages the RecyclerView's content. Next, direct the class to extend the RecyclerViewScrollbar.ValueLabelListener interface. For example, the below code shows an adapter class called NamesAdapter. The NamesAdapter class extends the Adapter class, which is required for any class that serves as a RecyclerView adapter, and the RecyclerViewScrollbar.ValueLabelListener interface, which is required to display a value label with the scrollbar:

import androidx.recyclerview.widget.RecyclerView.Adapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.codersguidebook.recyclerviewfastscroller.RecyclerViewScrollbar

class NamesAdapter : Adapter<ViewHolder>(), RecyclerViewScrollbar.ValueLabelListener {

The RecyclerViewScrollbar.ValueLabelListener interface requires the class to implement a method called getValueLabelText. The getValueLabelText method determines what text should be displayed in the value label at a given scroll position. For example, the NamesAdapter class described above will populate the RecyclerView with a list of names. In the value label for the RecyclerView's scrollbar, suppose we wanted to display the first character of the name displayed at the user's scroll position. If the list of names loaded into the RecyclerView was stored in a variable called names, then this could be achieved using the following code:

class NamesAdapter : Adapter<ViewHolder>(), RecyclerViewScrollbar.ValueLabelListener {
    var names = listOf<String>()

    override fun getValueLabelText(position: Int): String {
        return names[position][0].uppercase()
    }
recyclerview-scrollbar-fast-scroller-value-label.png

Customising the scrollbar's properties

For the final section of this tutorial, we will discuss the scrollbar's customisable properties. These properties can be assigned to the RecyclerViewScrollbar element in your XML layout files, and allow you to change the size and colour of various scrollbar components. A full list of the scrollbar's customisable properties and an explanation of what each property does is provided below:

To demonstrate how some of the above properties could be used, the below XML code shows how to define a RecyclerViewScrollbar element with a 300sp width and a value with a white background and navy blue text:

<com.codersguidebook.recyclerviewfastscroller.RecyclerViewScrollbar
    android:id="@+id/scrollbar"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    app:thumbAndTrackWidth="300sp"
    app:valueLabelBackgroundColor="@color/white"
    app:valueLabelTextColor="@color/navyBlue"
    app:layout_constraintEnd_toEndOf="@id/recyclerView" />

<<< Previous

Next >>>