13

My requirements are to display a vertical list of views with a scrollbar whenever the total height of the views is bigger than the allowed height for the list.

Additionally, I need to customize the scrollBar appearance (background and thumb) programmatically. (At runtime, my activity will receive all the data to do the rendering : the bitmap to use as scrollbar background, the scrollbar width and the bitmap to use as scrollbar's thumb.)

A ListView seems a good candidate for this, except that I can't find a way to customize the scrollBar programmatically. I read this question scrollBar in a listView...customizing it. but, it's using a theme, and AFAIK it's not possible the create a new theme programmatically.

So my question(s):

  1. Is there a way to customize the appearance of a scrollbar (within a ListView) programmatically ?

  2. [only if the answer to the first one is "definitively not possible"] do you see any other way to achieve those requirements (and some working example of doing it)

Thanks.

EDIT (23/12)

I found this hidden class android.widget.ScrollBarDrawable. May be a good starting point to build a solution (no time to investigate it right now).

5 Answers 5

6
+50

is there a way to customize the appearance of a scrollbar (within a ListView) programmatically ?

Literally, it does not look like it, simply because there are no setters for manipulating it.

It is conceivable that you could create your own BenView subclass of View that replaces the hidden ScrollBarDrawable with BenScrollBarDrawable that handles dynamic changes. But then you would need to create BenViewGroup, BenAbsListView, and BenListView, cloning their Ben-less counterparts' source code, to have them chain up to BenView to inherit this behavior. And, since one of ViewGroup, AbsListView, or ListView is bound to change in any Android release, you will actually need N copies of these classes and choose the right copy based on API level at runtime. And then your app may still behave oddly on some devices where the manufacturer went in and tinkered with ViewGroup, AbsListView, or ListView, and you will not be using their code.

I doubt that this is worth it, particularly since scrollbars are not visible by default except while scrolling.

do you see any other way to achieve those requirements (and some working example of doing it)

Handle your own touch events to do your own scrolling and do your own scrollbar stuff. Whether this is less work than the above solution is up for debate.

Sign up to request clarification or add additional context in comments.

Comments

3

I just faced the same problem for RecyclerView and solved it like this

import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.support.annotation.ColorInt; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; /** * Created on 22.3.2016. * * @author Bojan Kseneman * @description A recycler view that will draw the scroll bar with a different color */ public class CustomScrollBarRecyclerView extends RecyclerView { private int scrollBarColor = Color.RED; public CustomScrollBarRecyclerView(Context context) { super(context); } public CustomScrollBarRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomScrollBarRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setScrollBarColor(@ColorInt int scrollBarColor) { this.scrollBarColor = scrollBarColor; } /** * Called by Android {@link android.view.View#onDrawScrollBars(Canvas)} **/ protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) { scrollBar.setColorFilter(scrollBarColor, PorterDuff.Mode.SRC_ATOP); scrollBar.setBounds(l, t, r, b); scrollBar.draw(canvas); } /** * Called by Android {@link android.view.View#onDrawScrollBars(Canvas)} **/ protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) { scrollBar.setColorFilter(scrollBarColor, PorterDuff.Mode.SRC_ATOP); scrollBar.setBounds(l, t, r, b); scrollBar.draw(canvas); } } 

These methods are defined in View class, so the same princible should work of other views like ScrollView and ListView.

2 Comments

It is streching the scroll to match_parent.
you mean the scrollbar is as wide as it's parent or what?
0

Just change the android:scrollbarThumbVertical="@drawable/scrollbar_vertical_thumb" and create a drawable as per your need.

Like

<ListView android:scrollbarThumbVertical="@drawable/scrollbar_vertical_thumb" /> 

in the Drawable:

<shape xmlns:android="http://schemas.android.com/apk/res/android" > <gradient android:angle="0" android:endColor="#6699FF" android:startColor="#3333FF" /> <corners android:radius="1dp" /> <size android:width="1dp" /> </shape> 

I think this is what you want!

1 Comment

Sorry, but I think you didn't understand the question: I need to do it programmatically not with static xml.
0

If you only need to support API 24 or later, you can use a custom drawable to accomplish this task. You'll need to decide how you're going to allow the drawable to communicate with the activity. Here is one possible solution.

res/drawable/my_custom_scrollbar_thumb.xml

<com.example.RegisteredMutableDrawable android:id="@+id/scroll_thumb" />

res/drawable/my_custom_scrollbar_track.xml

<com.example.RegisteredMutableDrawable android:id="@+id/scroll_track" />

somewhere in your layout file

<ListView android:scrollbarTrackVertical="@drawable/my_custom_scrollbar_track" android:scrollbarThumbVertical="@drawable/my_custom_scrollbar_thumb"

the drawable implementation

public class RegisteredMutableDrawable extends DrawableWrapper { public static interface Registrar { public void register(int _id, RegisteredMutableDrawable _drawable); } public static Registrar registrar; private static int[] ATTRS = new int[] { android.R.attr.id }; public RegisteredMutableDrawable() { super(null); } public void inflate(Resources _res, XmlPullParser _parser, AttributeSet _as, Theme _theme) throws XmlPullParserException, IOException { super.inflate(_res, _parser, _as, _theme); final Registrar r = registrar; if (r != null) { final TypedArray ta = _res.obtainAttributes(_as, ATTRS); final int id = ta.getResourceId(0, 0); ta.recycle(); r.register(id, this); } } } 

in your activity

public class MyActivity extends Activity implements RegisteredMutableDrawable.Registrar { @Override public void onCreate(Bundle _icicle) { super.onCreate(_icicle); RegisteredMutableDrawable.registrar = this; setContentView(R.layout.whatever); RegisteredMutableDrawable.registrar = null; // don't leak our activity! } @Override public void register(int _id, RegisteredMutableDrawable _drawable) { switch(_id) { case R.id.scroll_thumb: _drawable.setDrawable(myThumbDrawable); break; case R.id.scroll_track: _drawable.setDrawable(myTrackDrawable); break; } } } 

Comments

-1

You can use the jquery plugin(jquery.nicescroll.js) to achieve this. More details visit http://areaaperta.com/nicescroll/

1 Comment

sorry, not looking for a browser solution

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.