13

I know listview can set scrollbar thumb in XML like this Android:scrollbarThumbVertical etc.

But I'm creating a listview instance in the java code and I maybe need to set different scrollbar thumb. Is there a method can set scrollbar thumb programmatically?

Sathyajith Bhat
  • 21,321
  • 22
  • 95
  • 134
dreamtale
  • 2,905
  • 1
  • 26
  • 38

4 Answers4

26

You can achieve that via reflection:

try
{
    Field mScrollCacheField = View.class.getDeclaredField("mScrollCache");
    mScrollCacheField.setAccessible(true);
    Object mScrollCache = mScrollCacheField.get(listview);
    Field scrollBarField = mScrollCache.getClass().getDeclaredField("scrollBar");
    scrollBarField.setAccessible(true);
    Object scrollBar = scrollBarField.get(mScrollCache);
    Method method = scrollBar.getClass().getDeclaredMethod("setVerticalThumbDrawable", Drawable.class);
    method.setAccessible(true);
    method.invoke(scrollBar, getResources().getDrawable(R.drawable.scrollbar_style));
}
catch(Exception e)
{
    e.printStackTrace();
}

The above code executes as:

listview.mScrollCache.scrollBar.setVerticalThumbDrawable(getResources().getDrawable(R.drawable.scrollbar_style));
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
  • 1
    Hi, @Eng.Fouad above solution is not working in recyclerview..even /*listview.mScrollCache.scrollBar.setVerticalThumbDrawable(getResources().getDrawable(R.drawable.scrollbar_style))*/ this line is not working with listview or recyclerview. – Mushtakim Ahmed Ansari Oct 12 '17 at 12:02
  • Triggers an error on API 29: `java.lang.NoSuchMethodException: android.widget.ScrollBarDrawable.setVerticalThumbDrawable [class android.graphics.drawable.Drawable]` – Prof Mar 18 '21 at 22:13
  • for API 29, we can just call setVerticalScrollbarThumbDrawable(drawable) – Randy Sugianto 'Yuku' Apr 05 '21 at 10:26
3

I modified the answer to make it a method 100% programmatically

public static void ChangeColorScrollBar(View Scroll, int Color, Context cxt){
   try
   {
       Field mScrollCacheField = View.class.getDeclaredField("mScrollCache");
       mScrollCacheField.setAccessible(true);
       Object mScrollCache = mScrollCacheField.get(Scroll);
       Field scrollBarField = mScrollCache.getClass().getDeclaredField("scrollBar");
       scrollBarField.setAccessible(true);
       Object scrollBar = scrollBarField.get(mScrollCache);
       Method method = scrollBar.getClass().getDeclaredMethod("setVerticalThumbDrawable", Drawable.class);
       method.setAccessible(true);

       Drawable[] layers = new Drawable[1];
       ShapeDrawable sd1 = new ShapeDrawable(new RectShape());
       sd1.getPaint().setColor(cxt.getResources().getColor(Color));
       sd1.setIntrinsicWidth(Math.round(cxt.getResources().getDimension(R.dimen.dp_3)));
       layers[0] = sd1;

       method.invoke(scrollBar, layers);
   }
   catch(Exception e)
   {
       e.printStackTrace();
   }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
toni
  • 1,674
  • 1
  • 15
  • 15
2

I didn't know the answer to this, but after a bit of digging around I don't think it's possible without a load of hassle.

This xml attribute is actually associated with a View, not a ListView - In the Android View source code, it seems that the only place that it is setting the vertical thumb drawable is the 'initializeScrollbars' method. Now this method isn't private, so we can extend any child of View and override this method, but the issue is that a crucial component needed to set the thumb drawable, the ScrollabilityCache, is private without any getter methods.

So without rewriting a lot of the code I don't think there's any easy way to do this - sorry!

Martyn
  • 16,432
  • 24
  • 71
  • 104
0

Starting from Android Q (API level 29), you can use setVerticalScrollbarThumbDrawable() & setHorizontalScrollbarThumbDrawable():

scrollView.verticalScrollbarThumbDrawable = 
                       ResourcesCompat.getDrawable(resources,     
                       R.drawable.scrollview_thumb, null)
Zain
  • 37,492
  • 7
  • 60
  • 84