How to use RippleDrawable programmatically in code (not xml) with Android 5.0 Lollipop? How to use RippleDrawable programmatically in code (not xml) with Android 5.0 Lollipop? android android

How to use RippleDrawable programmatically in code (not xml) with Android 5.0 Lollipop?


This is how I was able to achieve this.

Note that this is Api 21+ only so you will have to fallback to a normal Drawable if you support lower versions.

public static RippleDrawable getPressedColorRippleDrawable(int normalColor, int pressedColor){    return new RippleDrawable(getPressedColorSelector(normalColor, pressedColor), getColorDrawableFromColor(normalColor), null);}public static ColorStateList getPressedColorSelector(int normalColor, int pressedColor){    return new ColorStateList(        new int[][]            {                new int[]{android.R.attr.state_pressed},                new int[]{android.R.attr.state_focused},                new int[]{android.R.attr.state_activated},                new int[]{}            },        new int[]            {                pressedColor,                pressedColor,                pressedColor,                normalColor            }    );}public static ColorDrawable getColorDrawableFromColor(int color){    return new ColorDrawable(color);}

Edit:I tinkered with this some more and discovered that the ColorStateList doesn't need to be nearly as complex as the above solution. I have simplified it to the below snippet. (Everything else in the above code block is the same. I only changed the ColorStateList creation.) I will leave the above block as the original, in case this method doesn't work for someone.

new ColorStateList(    new int[][]        {            new int[]{}        },    new int[]        {            pressedColor        });


public static Drawable getAdaptiveRippleDrawable(    int normalColor, int pressedColor) {    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {        return new RippleDrawable(ColorStateList.valueOf(pressedColor),                null, getRippleMask(normalColor));    } else {        return getStateListDrawable(normalColor, pressedColor);    }}private static Drawable getRippleMask(int color) {    float[] outerRadii = new float[8];    // 3 is radius of final ripple,     // instead of 3 you can give required final radius    Arrays.fill(outerRadii, 3);    RoundRectShape r = new RoundRectShape(outerRadii, null, null);    ShapeDrawable shapeDrawable = new ShapeDrawable(r);    shapeDrawable.getPaint().setColor(color);    return shapeDrawable;}public static StateListDrawable getStateListDrawable(    int normalColor, int pressedColor) {    StateListDrawable states = new StateListDrawable();    states.addState(new int[]{android.R.attr.state_pressed},         new ColorDrawable(pressedColor));    states.addState(new int[]{android.R.attr.state_focused},         new ColorDrawable(pressedColor));    states.addState(new int[]{android.R.attr.state_activated},         new ColorDrawable(pressedColor));    states.addState(new int[]{},         new ColorDrawable(normalColor));    return states;}

You can get the drawable and apply to any view using view.setDrawable.
For Lollipop+ devices you will get ripple else it will change the color of view.


Basically, you need to create a new RippleDrawable object. For pre-Lollipop devices, you want a StateListDrawable (as others already suggested). I've written a somewhat resourceful GIST with a bunch of useful methods related to Drawables and coloring:https://gist.github.com/milosmns/6566ca9e3b756d922aa5

Most likely you will want to use #getBackgroundDrawable() from that singleton.