I have an Android project where I'm changing the color of the Ripple effect that happens in one of my views using the following approach
Although it's working, I do need to reset this color back to it's default value, based on my style. Bellow I'll show my Style file, and I'd love to have a way to set the RippleDrawable back to it's default color.
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="editTextColor">@android:color/white</item>
<item name="font">@font/roboto_regular</item>
<item name="colorControlNormal">@android:color/white</item>
<item name="android:scrollbarThumbVertical">@drawable/nice_scrollbar</item>
<item name="android:textColor">@color/darkGrey</item>
<item name="android:editTextColor">@android:color/black</item>
<item name="android:textColorHighlight">@color/colorPrimary</item>
<item name="android:colorBackground">@color/darkerWhite</item>
<item name="android:windowBackground">@color/darkerWhite</item>
<item name="windowNoTitle">true</item>
<item name="android:windowNoTitle">true</item>
</style>
As it can be noticed, I'm using MaterialComponents.
Below you'll find the current method I'm using to change color and also force the ripple effect on the view at a given x/y:
private void forceRippleAnimation(View view, int x, int y) {
Drawable background = view.getBackground();
if (Build.VERSION.SDK_INT >= 21 && background instanceof RippleDrawable) {
RippleDrawable rippleDrawable = (RippleDrawable) background;
rippleDrawable.setHotspot(x, y);
rippleDrawable.setColor(new ColorStateList(
new int[][]{
new int[]{}
},
new int[]{
getContext().getResources().getColor(R.color.rippleColor)
}
));
rippleDrawable.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled});
Handler handler = new Handler();
handler.postDelayed(new Runnable(){
@Override public void run(){
rippleDrawable.setState(view.getDrawableState());
}
}, 650);
}
}
Instead of trying to reverse the changes made to the original background
RippleDrawable, you can keep it and apply the changes to a copy:Let the
Activityhave twoDrawablefields:Create a copy of the given background and set it as the new background:
Since backgroundFromXml is a field, you can access it later on to reset the background to its original value:
What does
mutate()do?All
Drawables generated from one drawable resource share a common state. This helps saving resources (e.g. memory) and so will improve the performance of an android application.Normally, if you apply for example a
ColorFilterto aDrawablegenerated from a certain drawable resource, you will notice the effect everywhere in your app where this specific drawable resource is used.Calling
mutate()on aDrawabletells the runtime that thisDrawableshould have its own state. If you apply any changes afterwards, the other Drawables wil remain unchanged.See also the documentation on
mutate()