51

I've always been using android:background="?selectableItemBackground" for a ripple effect when a view (a LinearLayout for example) is clicked. I think I read somewhere that this is backwards compatible to API 14.

However, I've found that I need to use this ripple effect but with a white background. Specifically, I have a layout for a list item that will be displayed on the default color background (I'm extending from Theme.AppCompat.Light.NoActionBar), so I want the list item to stand out from this background by coloring the list item plain white (#FFFFFF).

Here is the list item layout:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="?selectableItemBackground"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    ...

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:paddingLeft="@dimen/mdu_keyline_1"
        android:paddingRight="@dimen/mdu_keyline_1"
        android:paddingTop="@dimen/mdu_padding_normal"
        android:paddingBottom="@dimen/mdu_padding_normal">

        ...

    </LinearLayout>

</FrameLayout>

The above produces the ripple effect without the white background.

If I try:

<FrameLayout ...
    android:background="@color/white">

This obviously produces a white background but without the ripple effect.

I also tried something else - and this produced a result closest to what I am looking for:

<FrameLayout ...
    android:background="@color/white">

    ...

    <LinearLayout ...
        android:background="?selectableItemBackground">

The above gave me the white background with a ripple effect. However, the ripple always seems to start from the center regardless of which part of the item I click.

Here are some screenshots showing the current result (ignore the shadow at the top of the list items - this is the shadow from the AppBarLayout and Toolbar I am using).

enter image description here

enter image description here

How could I achieve the desired effect?

Farbod Salamat-Zadeh
  • 19,687
  • 20
  • 75
  • 125

4 Answers4

108

You can use the foreground of your FrameLayout :

<FrameLayout ...
    android:background="@android:color/white"
    android:foreground="?attr/selectableItemBackground">
pdegand59
  • 12,776
  • 8
  • 51
  • 58
36

You can create a layer-list in your drawables folder, and set this to your background:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/white"/>
    <item android:drawable="?attr/selectableItemBackground"/>
</layer-list>
Marcel50506
  • 1,280
  • 1
  • 14
  • 32
  • When I am using ripple in drawable folder, at Android 6.0 this cause errors then I created a question please checkout : [binary-xml-file-line-error-inflating-class-unknown](http://stackoverflow.com/questions/38862718/binary-xml-file-line-error-inflating-class-unknown). Did you tried this way in Android 6.0 ? – Yasin Kaçmaz Aug 26 '16 at 14:30
  • Does this also happen when you use this as a background drawable (instead of foreground)? I'm currently using the exact layer-list above in one of my apps, it runs fine on Android six. I'm using support libs 23.4.0. – Marcel50506 Aug 26 '16 at 14:38
  • Yes I tried to use as background. Maybe this is a CardView issue. Didnt tried to use with normal View. – Yasin Kaçmaz Aug 26 '16 at 14:40
  • In CardView you must use as android:foreground – Yasin Kaçmaz Aug 26 '16 at 14:46
  • Just applied it to a CardView as foreground, i'm not getting any errors, I'm using Android 6 – Marcel50506 Aug 26 '16 at 15:00
  • Thanks I'll use it with CardView. – Yasin Kaçmaz Aug 26 '16 at 15:01
  • I think this answer is better than the selected one as it uses the `selectableItemBackground`... in the background. For example, I'm worried it may draw over a content, so it's better to use it in the background instead of in the foreground. – stan0 Feb 01 '19 at 12:32
  • Great solution! – Zakhar Rodionov Nov 15 '19 at 09:14
5

Ripple drawable is a LayerDrawable . So the right way to do this is :

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="?attr/colorControlHighlight">

    <item>
        <shape>
            <solid
                android:color="#FFFFFF"/>
        </shape>
    </item>

    <item android:id="@android:id/mask">
        <shape>
            <solid android:color="@android:color/white"/>
        </shape>
    </item>

</ripple>
Teovald
  • 4,369
  • 4
  • 26
  • 45
5

The other answers does work somewhat, but the following only works best for me:

In styles.xml add colorControlHighlight

  <style name="ExampleTheme" parent="Theme.AppCompat">
    <item name="colorAccent">...</item>
    <item name="colorPrimary">...</item>
    <item name="colorPrimaryDark">...</item>
    ...
    <item name="colorControlHighlight">@color/purple_bg</item> <-- THIS LINE
    ...
  </style>

</resources>

In colors.xml add color of your choice with a bit of alpha #77632E8E

<?xml version="1.0" encoding="UTF-8" ?>
<resources>

  <color name="purple_bg">#77632E8E</color>

</resources>

In AndroidManifest.xml set the theme on your activity (all of them)

<activity android:name=".MainActivity"
      ...
      android:theme="@style/ExampleTheme"
      ... />

In the Activity's layout main_layout.xml set the android:background on the view you want the effect on:

<LinearLayout
    android:id="@+id/llBlock"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:background="?attr/selectableItemBackgroundBorderless">
    ....
</LinearLayout>

Both ?attr/selectableItemBackground and ?attr/selectableItemBackgroundBorderless works

Pierre
  • 8,397
  • 4
  • 64
  • 80
  • just a small comment, theme can be applied to a single View, for example TextView and it will correctly use the colorControlHighlight property – abdu Feb 22 '21 at 15:33