Reputation: 178
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);
}
}
Upvotes: 1
Views: 256
Reputation: 13019
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 Activity
have two Drawable
fields:
private RippleDrawable customRippleDrawable;
private RippleDrawable backgroundFromXml;
Create a copy of the given background and set it as the new background:
Drawable background = view.getBackground();
if (Build.VERSION.SDK_INT >= 21 && background instanceof RippleDrawable) {
backgroundFromXml = (RippleDrawable) background;
customRippleDrawable = (RippleDrawable) background.getConstantState().newDrawable().mutate();
customRippleDrawable.setHotspot(x, y);
customRippleDrawable.setColor(new ColorStateList(
new int[][]{
new int[]{}
},
new int[]{
MainActivity.this.getResources().getColor(R.color.rippleColor)
}
));
customRippleDrawable.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled});
view.setBackground(customRippleDrawable);
}
Since backgroundFromXml is a field, you can access it later on to reset the background to its original value:
view.setBackground(backgroundFromXml);
What does mutate()
do?
All Drawable
s 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 ColorFilter
to a Drawable
generated from a certain drawable resource, you will notice the effect everywhere in your app where this specific drawable resource is used.
Calling mutate()
on a Drawable
tells the runtime that this Drawable
should have its own state. If you apply any changes afterwards, the other Drawables wil remain unchanged.
See also the documentation on mutate()
Upvotes: 2