Listview selector with colored background and ripple effect
Asked Answered
K

6

55

Standard ListView selector in android L developer preview uses colorControlHighlight for the ripple effect on touch and has a transparent background in unfocused state.

I would like to define a ListView item that has a colored background and still shows the ripple effect on touch with the same highlight color. Now, if I define the following drawable:

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="?android:colorControlHighlight">
    <item android:drawable="@color/my_background_color"/>
</ripple>

it works, but the ripple starts in the middle of the ListView item, regardless of the touch position. If I use the same background outside of the ListView, e.g. for a LinearLayout, it works like expected (the ripple starts on the touch position).

Kincaid answered 22/8, 2014 at 9:14 Comment(4)
Are you specifying the background on your list item and setting the list selector null?Haletta
Can you simply set your list item background to be a color and leave the list selector at the default value? ListView has special handling of touch events that will probably prevent you from getting the effect you want otherwise (though feel free to file a bug at code.google.com/p/android-developer-preview/wiki/… about this).Haletta
Setting the list item background to a solid color will not work, this will draw over the list selector. As mentioned in the question, setting the ripple selector as the item background doesn't receive the touch hotspot from the ListView. I've decided to follow the pattern of not setting any list item backgrounds and just setting the ripple as the listSelector. The only fault with this is I cannot have some list items with different backgrounds and keep the ripple, for example to highlight an unread message.Claustrophobia
Did you managed to fix this issue? I'm facing the same right now...Holcomb
H
127

I've managed to get individually colored list items while maintaining the ripple effect. Set the background of your list items using whatever adapter you have and set the listview to show the selector on top:

<ListView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:drawSelectorOnTop="true" />

This will draw the ripple effect above the background.

Horsehair answered 20/11, 2014 at 0:50 Comment(9)
Without setting drawSelectorOnTop to true, the ripple does not behave correctly in a ListView. For me, it was just filling the button with the ripple color, not the showing the actual effect. This fixed it - thanks!Infest
This answer just helped me fix one of those 6 hour bugs. Thank you so much.Restraint
This is actually the best and most simplest answer to solve this annoying problem.Paediatrician
With this I get the ripple but after the ripple disappears the color specified in the item drawable completely covers the whole cell not showing the content in it. Does anyone know how to fix that?Motion
this will not work if you have any buttons inside your custom row view.Aubin
@Motion then just set the individual list_view_item background.. then put no android:selector on the list viewManteau
Thanks did the trick, can you explain why ripple failed to show without drawing selector on top?Auriol
It doesn't do anything.Madrigalist
silver bullet comment!Maneating
S
6

As far as I can tell this bug is only in Android 5.0, not 5.1. The trick seems to be to use Drawable#setHotspot as a Google dev hints to here https://twitter.com/crafty/status/561768446149410816 (because obscure twitter hints are a great form of documentation!)

Assume you have a row layout something like this

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

      <LinearLayout
            android:id="@+id/row_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:background="?attr/selectableItemBackground">

          .... content here .....

     </LinearLayout>

</FrameLayout>

The following worked for me

            row.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    v.findViewById(R.id.row_content)
                        .getBackground()
                        .setHotspot(event.getX(), event.getY());

                    return(false);
                }
            });
Shuffle answered 11/6, 2015 at 1:55 Comment(0)
W
3

I've found that it only seems to work correctly if you apply the background to the root element of the list item.

Also, consider using the new RecyclerView instead of a ListView

List item view example:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/list_padding"
    android:layout_marginLeft="@dimen/list_padding"
    android:layout_marginRight="@dimen/list_padding"
    android:padding="@dimen/list_padding"
    android:background="@drawable/ripple_bg">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Large Text"
        android:id="@+id/tvTitle"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Small Text"
        android:id="@+id/tvSubtitle" />

</RelativeLayout>
Whited answered 17/11, 2014 at 0:20 Comment(2)
This is the answer I was looking for, it's the root of the problem I think.Tabshey
i have one recyclerview and i have a row layout with root Linear layout having imageview, textview. i have added android:background="@drawable/ripple_recycler_view_row" android:clickable="true" android:drawSelectorOnTop="true" to my root Linear layout but ripple is showing in background of clecked row element.Ammadas
T
3

The sample layout, which contains the Ripple effect as Background of the the parent layout.

<RelativeLayout 
                android:id="@+id/id4"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/ripple_effect"
                android:clickable="true">

                <ImageView 
                    android:id="@+id/id3"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentLeft="true"
                    android:background="@drawable/image"
                    android:layout_centerVertical="true"/>

                <LinearLayout
                    android:id="@+id/id2" 
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true">

                    <TextView 
                        android:id="@+id/id1"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/text"/>

                </LinearLayout>
            </RelativeLayout>

Ripple_effect.xml Here you can use any colour of you choice. Make sure that you use sdk version 21 and have drawable-v21 and style-v21 folder and put all the file related to v21 in them.

<ripple xmlns:android="http://schemas.android.com/apk/res/android" 
                  android:color="?android:colorControlHighlight">
    <item android:id="@android:id/mask">
        <shape android:shape="oval">
            <solid android:color="?android:colorAccent" />
        </shape>
    </item>

Here you can use different shape like rectangle instead of oval...

Trinidadtrinitarian answered 26/12, 2014 at 7:28 Comment(0)
L
3

i adapted @ArhatBaid 's answer a littlebit, tested it and it works perfectly:

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:colorControlHighlight">
    <item android:drawable="@color/light_grey_header_navigation_drawer"/>
</ripple>

So, this allows you to set a background color and still have the ripple effect.
for me target and minSdk are 21.

Laxation answered 20/1, 2015 at 11:18 Comment(0)
O
2

You can achieve this with a nested Layout. Just create e.g. a LinearLayout as root layout around your existing layout, set the ripple effect on the root layout and your background color to the nested one.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/ripple_effect"
    android:orientation="vertical">

    <RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/containterContent"
        android:background="@color/yourCOLOR"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!-- Your content -->

    </RelativeLayout>
</LinearLayout>
Outburst answered 11/3, 2015 at 9:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.