Can't make spinner's scrollbar always visible (Android)
Asked Answered
M

6

7

I have such a problem - I want to make spinner's scrollbar always visible. But for spinner function

setScrollbarFadingEnabled(false);

causes crash with a NullExceptionPointer during drawing the GUI.

XML tags can't solve this problem too - it seems that spinner just ignore them.

Maybe there are another ways to move? For example, using of the custom scrollbar? If yes, how can I do this?

Thanks for your answers, Dmitry.

As I've been asked, here is LogCat error message for simple project with just a spinner in it:

AndroidRuntime(2252): FATAL EXCEPTION: main
AndroidRuntime(2252): java.lang.NullPointerException
AndroidRuntime(2252): at android.view.View.onDrawScrollBars(View.java:5836)
AndroidRuntime(2252): at android.view.View.draw(View.java:6799)
AndroidRuntime(2252): at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
AndroidRuntime(2252): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
AndroidRuntime(2252): at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
AndroidRuntime(2252): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
AndroidRuntime(2252): at android.view.View.draw(View.java:6796)
AndroidRuntime(2252): at android.widget.FrameLayout.draw(FrameLayout.java:352)
AndroidRuntime(2252): at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
AndroidRuntime(2252): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
AndroidRuntime(2252): at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
AndroidRuntime(2252): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
AndroidRuntime(2252): at android.view.View.draw(View.java:6796)
AndroidRuntime(2252): at android.widget.FrameLayout.draw(FrameLayout.java:352)
AndroidRuntime(2252): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2078)
AndroidRuntime(2252): at android.view.ViewRoot.draw(ViewRoot.java:1433)
AndroidRuntime(2252): at android.view.ViewRoot.performTraversals(ViewRoot.java:1175)
AndroidRuntime(2252): at android.view.ViewRoot.handleMessage(ViewRoot.java:1753)
AndroidRuntime(2252): at android.os.Handler.dispatchMessage(Handler.java:99)
AndroidRuntime(2252): at android.os.Looper.loop(Looper.java:123)
AndroidRuntime(2252): at android.app.ActivityThread.main(ActivityThread.java:4632)
AndroidRuntime(2252): at java.lang.reflect.Method.invokeNative(Native Method)
AndroidRuntime(2252): at java.lang.reflect.Method.invoke(Method.java:521)
AndroidRuntime(2252): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
AndroidRuntime(2252): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
AndroidRuntime(2252): at dalvik.system.NativeStart.main(Native Method)
Microdont answered 4/4, 2012 at 15:37 Comment(3)
Can we see some LogCat? Thank you.Deputation
does this happen on all api levels?Biplane
@Biplane I know for sure that happens since API 15. Not sure about minor levels.Yarmouth
B
9

Spinner does not have a scrollbar, Hence you are getting NullPointerException.

The popup shown by spinner has a scrollbar. So you need to change the properties of the ListView shown by spinner. But ListView itself is not exposed by Spinner by any public methods.

Even if you get the ListPopupWindow by reflection, a further problem arises, that ListPopupWindow's ListView is only created after you click the Spinner.

But OnClickListener of the Spinner cannot be registered , to set the ListView Properties after the show.

You could create a Custom Spinner with performClick overridden and then get mPopup by reflection. and use mPopup.getListView().setScrollbarFadingEnabled(false)

But If you are going to create a custom Spinner, i believe it is easier to implement the whole popup to suit your needs than using reflection.

Biplane answered 28/9, 2012 at 17:17 Comment(1)
OK, thanks for the answer, it's practically the same I thought. Pretty sad.Microdont
T
2

Thank @nandeesh for his/her answer and also @Eng.Fouad for his/her answer on another page.

public class VisibleScrollbarSpinner extends Spinner {
    @Override public boolean performClick() {
        final boolean superResult = super.performClick();

        try {
            final Field mPopupField = Spinner.class.getDeclaredField("mPopup");
            mPopupField.setAccessible(true);
            //noinspection ConstantConditions
            ((ListPopupWindow) mPopupField.get(this)).getListView().setScrollbarFadingEnabled(false);
            mPopupField.setAccessible(false);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            Log.e(TAG, e.toString(), e);
        }

        return superResult;
    }

    public VisibleScrollbarSpinner(Context context) { super(context); } 
    public VisibleScrollbarSpinner(Context context, int mode) { super(context, mode); } 
    public VisibleScrollbarSpinner(Context context, AttributeSet attrs) { super(context, attrs); } 
    public VisibleScrollbarSpinner(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } 
    public VisibleScrollbarSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) { super(context, attrs, defStyleAttr, mode); }
}
Thales answered 25/11, 2017 at 16:1 Comment(0)
C
1

in your app theme or activity them :

  <item name="android:dropDownListViewStyle">@style/SpinnerStyle1</item>

declare SpinnerStyle1:

<style name="SpinnerStyle1" parent="Widget.AppCompat.ListView.DropDown">
        <item name="android:divider">@color/blackText</item>
        <item name="android:dividerHeight">1px</item>
          <item name="android:scrollbarAlwaysDrawVerticalTrack">true</item>
</style>
Cheep answered 12/9, 2020 at 9:5 Comment(0)
Y
0

After a initial investigation, I'm thinking that is not possible to call setScrollbarFadingEnabled(false); in a Spinner.

I have read the implementation of the Class Spinner.java and View.java (this last one implements the setScrollbarFadingEnabled(boolean) of the API16 and the problem is the line:

cache.scrollBar.setAlpha(255);

Probably cache.scrollBar is null at this point and i didnt find any way to force some initialization of this attribute.

The most methods who manage this attribute are protected or private, so we can't just call them.

I'll continue to research this problem in order to find a possible solution, but for now, and considering that nobody have answered this question yet, i'm thinking that is not possible.

Yarmouth answered 28/9, 2012 at 11:47 Comment(0)
P
0

I have noticed "setScrollbarFadingEnabled" java method and "fadeScrollbar" xml method both doesn't make any affect on spinner because the list view of spinner is wrapped up in a dialog (popup), so these properties doesn't reach the listview.

But what Actually reaches the spinner listview is THEME.

So just create a custom theme like this:

<style name="App_SpinnerStyle" >
        <item name="android:fadeScrollbars">false</item>
</style>

And add it to spinner like this:

android:popupTheme="@style/App_SpinnerStyle"

Tried and tested!

Periwinkle answered 23/11, 2019 at 6:41 Comment(0)
U
0

As it's not easy to access the underlying ListView of the spinner, I found a simple solution for this.

Create a style in styles.xml, And set scrollbarFadeDuration to some endless value.

<style name="AlwaysEnableScrollBar" parent="Widget.AppCompat.ListView.DropDown">
    <item name="android:scrollbarFadeDuration">10000000</item>
</style>

Then set that in the spinner theme:

<Spinner
    ...
    android:theme="@style/AlwaysEnableScrollBar"/>
Unpack answered 5/12, 2020 at 23:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.