I am making a custom button view that has a gradient border, rounded corners and a transparant background. I am setting the background of the button to the drawable generated by the following code:
protected Drawable getBackgroundDrawable() {
GradientDrawable backgroundDrawable = new GradientDrawable(
mOrientation,
mGradientColors);
backgroundDrawable.setCornerRadius(getHeight() / 2);
backgroundDrawable.setShape(GradientDrawable.RECTANGLE);
if (!mFilled) {
Bitmap background = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas backgroundCanvas = new Canvas(background);
backgroundCanvas.drawARGB(0, 0, 0, 0);
backgroundDrawable.setBounds(0, 0, getWidth(), getHeight());
backgroundDrawable.draw(backgroundCanvas);
Paint rectPaint = new Paint();
rectPaint.setAntiAlias(true);
rectPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
backgroundCanvas.drawRoundRect(new RectF(mStroke, mStroke,
getWidth() - mStroke,
getHeight() - mStroke),
getHeight() / 2,
getHeight() / 2,
rectPaint);
return new BitmapDrawable(getResources(), background);
} else {
return backgroundDrawable;
}
}
The only problem is, when you click the button now, you have no feedback. How can I add a ripple effect at the back of the button when I already use the generated drawable as a background? Do I have to do something with a LayerDrawable?
My button looks like this:
What I really want to achieve
Create a Drawable programmatically that has the same result as this XML drawable, where the item in the ripple element is my generated Drawable in the image above:
<ripple android:color="@android:color/black" xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/background"></item>
</ripple>
What I have tried
I now tried to make a RippleDrawable in combination with a GradientDrawable to recreate the XML above in code. Very easy, I thought:
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.TRANSPARENT);
gradientDrawable.setStroke(mStroke, Color.GREEN);
gradientDrawable.setCornerRadius(getHeight() / 2);
ColorStateList rippleStateList = ColorStateList.valueOf(Color.BLUE);
return new RippleDrawable(rippleStateList, gradientDrawable, gradientDrawable);
This returns a simple drawable with a green stroke. However, when you click it, nothing happens. Unlike the XML where you clearly can see a ripple effect over the border. When I set the third parameter to null
, same effect. When I only set the second parameter to null
it only returned an empty transparant drawable without any ripple effects.
You should use a
RippleDrawable
as the background of your custom button. TheRippleDrawable
has a mask layer, which is what you are looking for. To do this programmatically, you can create aRippleDrawable
like so:Keep in mind that
RippleDrawable
is only available for API Level 21+, so if you are looking to support older versions as well you will need to fall back to something else; possiblyandroid.R.attr.selectableItemBackground
or aStateListDrawable
, which will give your button a basic "pressed" background for older platform versions.