11

I tried to apply ripple effect on Spinner dropdown items, like this:

activity.java

    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.array_name, R.layout.simple_spinner_dropdown_item);
    adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
    Spinner mSpinner = (Spinner) findViewById(R.id.spinner);
    mSpinner.setAdapter(adapter);

simple_spinner_dropdown_item.xml

<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@android:id/text1"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="@drawable/spinner_ripple"
   android:ellipsize="marquee"
   android:gravity="center_horizontal"
   android:padding="10dip"
   android:singleLine="true"
   android:textSize="14sp" />

spinner_ripple.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
   <ripple android:color="?android:attr/colorControlHighlight">
       <item><shape>
                  <solid android:color="@android:color/white" />
              </shape>
       </item>
   </ripple>
</item>
</selector>

but in the dropdown list it works only for the first item and only if the current selected item is another one than the first. In all other cases it fills background item with ripple color (as no ripple effect). Where is wrong my code?

Already tried: doesnt work to set fixed color on background of dropdown item layout and move ripple effect under Spinner element, like this:

simple_spinner_dropdown_item.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@android:id/text1"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="@android:color/white"
   android:ellipsize="marquee"
   android:gravity="center_horizontal"
   android:padding="10dip"
   android:singleLine="true"
   android:textSize="14sp" />

activity_layout.xml

<Spinner
   android:id="@+id/spinner"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:drawSelectorOnTop="true"
   android:dropDownSelector="@drawable/spinner_ripple" />
GPack
  • 2,494
  • 4
  • 19
  • 50

3 Answers3

6

Your second approach is correct, but as mentioned in this question, android:dropDownSelector attribute does not work and it's a well known bug.

Also, if you want to change drop-down background color, you need to set Spinner's android:popupBackground, instead of setting the background of the drop-down item.

The whole solution will be like this:

popup_background.xml

<!--Based on Android's popup_background_material.xml-->
<!--This changes the background of the drop-down-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
    <corners android:radius="2dp" />
    <solid android:color="@android:color/white" />
</shape>

styles.xml

<resources>
    <style name="AppTheme" parent="android:Theme.Material.Light">
        <!--Workaround for the Android bug-->
        <item name="android:dropDownListViewStyle">@style/Theme.MyListView</item>
    </style>

    <style name="Theme.MyListView" parent="@android:style/Widget.Material.ListView.DropDown">
        <item name="android:listSelector">@drawable/spinner_ripple</item>
    </style>
</resources>

activity.xml

...
<Spinner
    android:id="@+id/spinner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:dropDownSelector="@drawable/spinner_ripple"
    android:popupBackground="@drawable/popup_background"
    />
...

spinner_ripple.xml (original)

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <ripple android:color="?android:attr/colorControlHighlight">
            <item>
                <shape>
                    <solid android:color="@android:color/white" />
                </shape>
            </item>
        </ripple>
    </item>
</selector>
Community
  • 1
  • 1
stealth
  • 371
  • 2
  • 8
  • In this way ripple effect on white background is moved on theme level: it works, but works for all spinners in my app. Thus I cant have a single spinner with ripple effect on his own background color different than the theme one. – GPack Jan 18 '15 at 10:48
  • That is unfortunate but due to the Android bug it's the only way, unless you want to subclass the spinner class and try to implement a workaround in there. – stealth Jan 18 '15 at 10:54
  • Btw, why do you want to have one spinner different from the others? – stealth Jan 18 '15 at 10:55
  • It is due to styling choice. It seems that there isn't another way, thus yours is the right one. Many thanks for helping me. – GPack Jan 18 '15 at 11:04
5

If you want to have your dropdown list items to be white by default and highlight them with ripple effect only when user touches them, you need to implement proper state list in the spinner_ripple.xml drawable:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <ripple android:color="?android:attr/colorControlHighlight" />
    </item>
    <item android:state_pressed="false">
        <shape>
            <solid android:color="@android:color/white" />
        </shape>
    </item>
</selector>

Here, android:state_pressed="true" means that selector item shall be applied only when user actually presses the view. If you want to support other selector states check out the StateListDrawable reference.

Keep in mind that AppCompat-v7 v21 does not support ripple effect, according to official Android Developers blog:

Why are there no ripples on pre-Lollipop? A lot of what allows RippleDrawable to run smoothly is Android 5.0’s new RenderThread. To optimize for performance on previous versions of Android, we've left RippleDrawable out for now.

So it will only work on Lollypop.

stealth
  • 371
  • 2
  • 8
0

I believe you need two layers in your spinner_ripple.xml

<!-- Background -->
<ripple android:color="#ff00ff00">
    <item android:drawable="@android:color/black" />
<ripple />

<!-- Ripple color -->
<ripple android:color="#ff00ff00">
    <item android:drawable="@android:color/white" />
<ripple />
Jonas Borggren
  • 2,591
  • 1
  • 22
  • 40
  • 1
    Two `ripple` elements at the same level in the xml under `selector`? I will try, but I think it is not the right way. Thanks. – GPack Jan 13 '15 at 15:55