How to make a circular ripple on a button when it's being clicked?
Asked Answered
N

13

164

Background

On the dialer app of Android, when you start searching for something, and you click the arrow button on the left of the EditText, you get a circular ripple effect on it :

enter image description here

The problem

I've tried to have it too, but I got a rectangular one:

    <ImageButton
        android:id="@+id/navButton"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="8dp"
        android:background="?android:attr/selectableItemBackground"
        android:src="@drawable/search_ic_back_arrow"/>

The question

How do I make the button have a circular ripple effect when being clicked? Do I have to create a new drawable, or is there a built in way for that?

Nealy answered 11/8, 2015 at 12:26 Comment(4)
github.com/traex/RippleEffect try thisCalumny
possible answer is here #33477525Triliteral
Consider changing your selected answer to the one with the most upvotes, as it actually solves the problemImre
@JeffBarger Why? Both work fine. There is no better one between them.Nealy
E
31

If you already have a background image, here is an example of a ripple that looks close to selectableItemBackgroundBorderless:

            <ImageButton
                android:id="@+id/btn_show_filter_dialog"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:background="@drawable/ic_filter_state"/>

ic_filter_state.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_pressed="true"
        android:state_enabled="true"
        android:drawable="@drawable/state_pressed_ripple"/>
    <item
        android:state_enabled="true"
        android:drawable="@drawable/ic_filter" />
</selector>

state_pressed_ripple.xml: (opacity set to 10% on white background) 1AFFFFFF

 <?xml version="1.0" encoding="UTF-8"?>    
    <ripple xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <shape android:shape="oval">
                <solid android:color="#1AFFFFFF"/>
            </shape>
            <color android:color="#FFF"/>
        </item>
    </ripple>
Ewall answered 20/4, 2018 at 2:54 Comment(1)
What happened if it is a layer list?Andryc
T
357

If you are using AppCompat theme, then you could set the background of the view as:

android:background="?selectableItemBackgroundBorderless"

This will add circular ripple on 21 and above and square background on below 21.

Thiele answered 21/12, 2015 at 3:0 Comment(15)
Nice. Can I also set the color of it somehow?Nealy
@androiddeveloper you might want to create your own custom style for it using ripple for v21+Thiele
So I guess tinting won't help?Nealy
in API 23 the 'up' background appears to be half the size in comparison to selectbleItemBackgroundBorderlessIndustrialize
@androiddeveloper, color can be set by setting colorControlHighlight like below in your styles.xml <item name="colorControlHighlight">#F00</item>Thiele
Above is the answer to show ripple, my previous comment was for setting different ripple color than the default color.Thiele
how to set it in java? android.R.attr.selectableItemBackgroundBorderless didn't workColb
@Thiele how can i make this same effect with custom colorsJonis
If you are using it inside other layouts, you might need android:clipChildren="false" in the layouts as well to allow the animation to propagate.Republic
@AbduazizKayumov It depends how you try it. Use something like that: https://mcmap.net/q/76249/-access-resource-defined-in-theme-and-attrs-xml-androidNealy
this solution is great for static images. However, I'm using an AppCompatImageView with frame-animation and the background is used for the animation, so this lovely one-liner doesn't work with that. I've tried android:foreground="?selectableItemBackgroundBorderless" and it gives a ripple, however, the ripple effect reveals a square - which is ugly.Anthotaxy
This should be the accepted answer. Worked on imageview with circular src drawableHoopen
It's not circular with ImageView in Android 9. Its squareHydrops
It is not working with the new MaterialComponents theme. Theme.MaterialComponentsCampion
If the ripple effect is not showing in dark mode then try adding android:theme="@style/Theme.AppCompat.Light.DarkActionBar" in your viewBufordbug
I
126

Another attribute with round ripple effect, specially for action bar:

android:background="?actionBarItemBackground"

UPD: Ripple color can be changed by this attribute:

<!--somewhere in styles-->
<item name="colorControlHighlight">your_color_here</item>

But keep in mind, this attribute applies to all default ripple effects.

Inhale answered 29/1, 2018 at 13:40 Comment(6)
Any way to customize it? For example the color? Maybe something in styles? Or even more specifically in the view XML tag itself?Nealy
I do not know, today I solved this problem and the answers above did not work as I needed. I assume that the color can be customized in styles, but definitely not in the view.Inhale
If you figure it out, please let me know. Could be useful.Nealy
This is exactly the right effect I'm looking for. By the way, can you mention where to find this attribute, it seems not be documented.Abiogenetic
@JackWang it is in "?attr/actionBarItemBackground"Skip
@MeysamHadigheh ? is shortcut for ?attr/Toll
P
56

Create and set a ripple drawable as background. Something like this.

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/grey_15">
    <item android:id="@android:id/mask">
        <shape android:shape="oval">
            <solid android:color="?android:colorPrimary"/>
        </shape>
        <color android:color="@color/white"/>
    </item>
</ripple>
Pickerelweed answered 11/8, 2015 at 12:29 Comment(11)
It's something in my code. You can use your colors :)Pickerelweed
How would I use the default selector in case it's on pre-Lollipop ? Also, does it use the same colors as the one on the dialer?Nealy
You can put the ripple drawable in your drawables-v21 folder. And for pre L use a simple state drawable. Use the same file name and put it into the drawable (default) folder.Pickerelweed
I mean, what should it have for pre-Lollipop, inside its drawable file? Also, please answer about the color. Is it possible to use the same one that's used for "selectableItemBackground" ?Nealy
Ripple is not available in pre-lollipop. So in the drawable file of pre-lollipop, ordinary button drawable is needed. <item name="state_pressed" color=" .... . . "Cattail
You can also create a style. In values-v21 folder create a new style and set the ripple drawable as background. And for pre L, i.e. in your values folder styles.xml put as background the "selectableItemBackground" attribute for the same style.Pickerelweed
@ThomasR. Can you please show exactly what to put? Also, what's the value of "grey_15" ?Nealy
According to my tests, this works only if the button has a square shape (width==height). when it's not, I get an elliptic shape. I've even tried to set the size of the drawable with equal width and height, but I still get this issue. How come?Nealy
<ripple> require api level 21 :)Mountford
If you want the same ripple color as the other default ripple effects used in the app, use "?attr/colorControlHighlight" as the color.Alimentary
I recommend to change the shape from oval to rectangle and then within the shape add something like <corners android:radius="8dp" />Imprisonment
S
45

Just Add this background to your view

"android:background=?android:attr/actionBarItemBackground"

Skillful answered 30/1, 2019 at 12:33 Comment(0)
E
31

If you already have a background image, here is an example of a ripple that looks close to selectableItemBackgroundBorderless:

            <ImageButton
                android:id="@+id/btn_show_filter_dialog"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:background="@drawable/ic_filter_state"/>

ic_filter_state.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_pressed="true"
        android:state_enabled="true"
        android:drawable="@drawable/state_pressed_ripple"/>
    <item
        android:state_enabled="true"
        android:drawable="@drawable/ic_filter" />
</selector>

state_pressed_ripple.xml: (opacity set to 10% on white background) 1AFFFFFF

 <?xml version="1.0" encoding="UTF-8"?>    
    <ripple xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <shape android:shape="oval">
                <solid android:color="#1AFFFFFF"/>
            </shape>
            <color android:color="#FFF"/>
        </item>
    </ripple>
Ewall answered 20/4, 2018 at 2:54 Comment(1)
What happened if it is a layer list?Andryc
V
23

You can create circle ripple drawable using android:radius attribute in xml.

Example:

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="your_color"
    android:radius="your_radius" />

Pay attention, that your your_radius should be less then your view width and height. For example: if you have view with size 60dp x 60dp your_radius should be near 30dp (width / 2 or height / 2).

Work on Android 5.0 and above.

Violoncellist answered 29/11, 2016 at 10:23 Comment(1)
I always look for how to setup radius explicitly. Thank you.Arevalo
M
9

update 2021:

you need use actionBarItemBackground for background

android:background="?android:attr/actionBarItemBackground"

Example:

 <androidx.appcompat.widget.AppCompatImageButton
        android:layout_width="56dp"
        android:layout_height="56dp"
        android:background="?android:attr/actionBarItemBackground"
        android:src="@drawable/ic_copy" />
Moray answered 20/6, 2021 at 13:1 Comment(0)
C
7

just add this item in your activity xml

           <ImageButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="?android:attr/actionBarItemBackground"
                app:srcCompat="@drawable/ic_arrow_drop_down_black_24dp" />
Canara answered 1/3, 2020 at 13:1 Comment(1)
B
3

If you want more generic XML files, I have two files:

1) btn_ripple_background with code:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:state_pressed="true"
    android:state_enabled="true"
    android:drawable="@drawable/ripple_circular_shape"/>
</selector>

2) ripple_circuler_shape with code:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/btn_state_pressed_text_color"
    android:shape="oval">
    <solid android:color="@color/btn_state_pressed_text_color" />
</shape>

finally the usage:android:foreground="@drawable/ripple_btn_background"

Bourdon answered 11/1, 2019 at 14:4 Comment(0)
B
3

If you want ripple effect which will not cross the circle boundary, you can check this code. It works for me perfecrly. Just remember, you have to give id=@android:id/mask in ripple_blue.xml

<ImageButton
    android:id="@+id/send_password_to_mail_image_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/ripple_blue"
    android:src="@drawable/ic_filter" />

ripple_blue.xml

<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorRipple">

    <item android:id="@android:id/mask">

        <shape android:shape="oval">
            <solid android:color="@color/colorWindowBackground"/>
        </shape>

    </item>

    <item android:id="@android:id/background">

        <shape android:shape="oval">
            <solid android:color="@color/colorWindowBackground"/>
        </shape>

    </item>

</ripple>

color.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <color name="colorWindowBackground">#F2F5FC</color>
    <color name="colorRipple">#0288d1</color>
</resources>
Beavers answered 10/3, 2020 at 7:42 Comment(0)
H
1

Try:

android:background="@android:color/transparent"
android:clickable="true"
android:focusable="true"
android:foreground="?actionBarItemBackground"
Helmuth answered 17/11, 2019 at 4:16 Comment(2)
Please don't post only code as an answer, but include an explanation what your code does and how it solves the problem of the question. Answers with an explanation are generally of higher quality, and are more likely to attract upvotes.Geddes
Smoother than setting actionBarItemBackground as background. But still not exactly same as action bar animation itself.Myrwyn
A
1

I also fixed this problem in one of my projects. android:foreground="?attr/selectableItemBackgroundBorderless" is responsible for the ripple effect, that's why it is set in the foreground and android:clipToPadding="false" will prevent the ripple effect cut off and make it rectangular.It will keep your ripple effect circular.

<ImageButton
        android:id="@+id/navButton"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="8dp"
        android:foreground="?attr/selectableItemBackgroundBorderless"
        android:clipToPadding="false"
        android:src="@drawable/search_ic_back_arrow"/>
Andryc answered 4/1, 2021 at 11:14 Comment(1)
Not sure if you can put comments inside this way, and even then, you probably wanted to put each above. In addition, doesn't using selectableItemBackgroundBorderless mean it will be quite large for the case I've show (in a small area) ? Anyway, how do you change the color of the ripple this way?Nealy
W
0

In Kotlin / Java you can do the following

fun View.applyCircularRippleEffect() {
    val backgroundResId = context.getResource(android.R.attr.actionBarItemBackground)

    if (backgroundResId != 0) {
        setBackgroundResource(backgroundResId)
        isClickable = true
        isFocusable = true
    }
}

// getResource extension
fun Context.getResource(resourceId: Int): Int {
    val out = TypedValue()
    theme.resolveAttribute(resourceId, out, true)

    return out.resourceId
}
Wideranging answered 2/5, 2020 at 17:46 Comment(2)
context.getResource not foundLepage
@RahulMandaliya thank you for the comment. My bad, it was my custom extension method. Added it to the answerWideranging

© 2022 - 2024 — McMap. All rights reserved.