3

I want to reduce scrollbar size(attached image) for recycler view, I have tried with creating custom drawable for for Thumb & Track, but thumb is not underlying with in the track. Can someone help me in better approach to achieve this?

enter image description here

In above image, horizontal scrollbar at bottom which is small in size. I want to achieve something like this.

enter image description here

T_V
  • 17,440
  • 6
  • 36
  • 48
  • can you explain more clearly, please – Arsh Aug 02 '22 at 13:16
  • @Arsh In above image you can see horizontal scrollbar at bottom which is small in size. I want to achieve something like this. – T_V Aug 04 '22 at 18:53
  • so you want that when you slide recyclerview, the scrollbar moves with it. Or you just slide on the scrollbar below and the recyclerview scrolls by moving it – Arsh Aug 04 '22 at 21:04
  • https://stackoverflow.com/questions/46402973/android-how-to-make-custom-scroll-bar-for-recycler-view maybe this can help – Arsh Aug 04 '22 at 21:12
  • @Arsh so you want that when you slide recyclerview, the scrollbar moves with it. - YES, – T_V Aug 05 '22 at 03:53
  • you can also use the ViewPager for that. https://github.com/chahine/pageindicator – Aniruddh Parihar Aug 09 '22 at 14:09

2 Answers2

2

Here is one way that you can do what you want:

Define the thumb:

enter image description here

custom_thumb.xml

<shape
    android:shape="rectangle">
    <corners android:radius="20dp" />
    <solid android:color="@android:color/holo_red_light" />
    <size
        android:width="40dp"
        android:height="10dp" />
</shape>

Define the progress drawable for the seekbar:

seekbar_drawable.xml

<layer-list>
    <item android:id="@android:id/progress">
        <clip android:drawable="@android:color/transparent" />
    </item>
</layer-list>

We will not show the progress for the seekbar, so we set the progress drawable to "transparent". Instead of the progress drawable, we will define another view that will show behind the progress bar. Why do we do this? It is because the seekbar wants to move the thumb outside the progress area and we want the thumb to remain entirely within the progress area. The second view encompasses all of the seekbar plus some area to the left and to the right to contain the thumb.

seekbar_background.xml

<shape>
    <corners android:radius="20dp"/>
    <solid android:color="@android:color/darker_gray" />
</shape>

Here is some sample XML to show how this looks:

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">

    <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@drawable/seekbar_background"
        app:layout_constraintBottom_toBottomOf="@id/seekBar"
        app:layout_constraintEnd_toEndOf="@id/seekBar"
        app:layout_constraintStart_toStartOf="@id/seekBar"
        app:layout_constraintTop_toTopOf="@id/seekBar" />

    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:max="10000"
        android:min="0"
        android:paddingStart="20dp"
        android:paddingEnd="20dp"
        android:progressDrawable="@drawable/seekbar_drawable"
        android:thumb="@drawable/custom_thumb"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

enter image description here

Use a SeekBar.OnSeekBarChangeListener to scroll the RecyclerView using the RecyclerView's scrolling functions. When the RecyclerView is scrolled manually, use a RecyclerView.OnScrollListener to set the seekbar's progress. You will have to establish the mapping of the two views scroll states.

I have hard-coded some values that you will probably need to adjust.

One can change the width of the thumb programmatically with the following code to adjust for number of Recyclerview items or to any other value.

To change the width of the thumb by a factor of two as an example, you can do the following:

val thumb = binding.seekBar.thumb as GradientDrawable
thumb.setSize(thumb.intrinsicWidth * 2, thumb.intrinsicHeight)
Cheticamp
  • 61,413
  • 10
  • 78
  • 131
  • Thanks Cheticamp, This is very close to what I am looking for, But Thumb is of fixed size here, but as per my requirement thumb size will decrease as item in recyclerview will increase, can we set thumb size programmatically or any other way to achieve this. – T_V Aug 06 '22 at 11:12
  • thank you for that solution but, can you clarify how to use the scroll of the recycler to move the seek bar? – Moustafa EL-Saghier Nov 02 '22 at 13:10
1

You can create your own custom scrollbar and tie it with recycler view. Following is extension method for recycler view to handle the above made scrollbar

fun RecyclerView.handleScroll(itemScrollerBinding: ItemScrollerBinding) {
    post {
        val parentWidth = itemScrollerBinding.parent.width
        val layoutParams = itemScrollerBinding.progress.layoutParams
        val initialX = itemScrollerBinding.progress.x
        layoutManager?.let {
            val totalWidth = this.computeHorizontalScrollRange()
            val visibleWidth = this.computeHorizontalScrollExtent()
            val percent =
                visibleWidth.toFloat() / totalWidth.toFloat()
            layoutParams.width = (parentWidth * percent).toInt()
            itemScrollerBinding.progress.layoutParams = layoutParams
            addOnScrollListener(object :
                RecyclerView.OnScrollListener() {
                override fun onScrolled(
                    recyclerView: RecyclerView,
                    dx: Int,
                    dy: Int,
                ) {
                    super.onScrolled(recyclerView, dx, dy)
                    val scrolledWidth =
                        this@handleScroll.computeHorizontalScrollOffset()
                    val updatedVisibleWidthRecyclerView =
                        visibleWidth + scrolledWidth
                    val scrolledWidthScroller =
                        ((parentWidth.toFloat() / totalWidth) * scrolledWidth)
                    itemScrollerBinding.progress.x =
                        initialX + scrolledWidthScroller
                }
            })
        }
    }
}

Following is xml code for ItemScrollerBinding

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parent"
    android:layout_width="@dimen/size_48"
    android:layout_height="@dimen/size_6"
    android:background="@drawable/bg_scroller_background">
    <LinearLayout
        android:id="@+id/progress"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:background="@drawable/bg_scroller"
        android:orientation="horizontal" />
</FrameLayout>

You can place this below the recycler view and center it.

likhit
  • 21
  • 4