Make sparkle color and alpha customizable
This CL introduces a new attr: effectColor. The attribute can be used on ripple tags to customize the color and alpha of the ripple decoration. It's also possible to change the effect color via code by invoking RippleDrawable#setEffectColor. Fixes: 185602477 Test: atest RippleDrawableTest Change-Id: I9b50f330729a67ef4b529283a92c83c28387fa0b
This commit is contained in:
@@ -592,6 +592,7 @@ package android {
|
||||
field public static final int editTextStyle = 16842862; // 0x101006e
|
||||
field @Deprecated public static final int editable = 16843115; // 0x101016b
|
||||
field public static final int editorExtras = 16843300; // 0x1010224
|
||||
field public static final int effectColor;
|
||||
field public static final int elegantTextHeight = 16843869; // 0x101045d
|
||||
field public static final int elevation = 16843840; // 0x1010440
|
||||
field public static final int ellipsize = 16842923; // 0x10100ab
|
||||
@@ -16817,8 +16818,10 @@ package android.graphics.drawable {
|
||||
|
||||
public class RippleDrawable extends android.graphics.drawable.LayerDrawable {
|
||||
ctor public RippleDrawable(@NonNull android.content.res.ColorStateList, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable);
|
||||
method @NonNull public android.content.res.ColorStateList getEffectColor();
|
||||
method public int getRadius();
|
||||
method public void setColor(android.content.res.ColorStateList);
|
||||
method public void setColor(@NonNull android.content.res.ColorStateList);
|
||||
method public void setEffectColor(@NonNull android.content.res.ColorStateList);
|
||||
method public void setRadius(int);
|
||||
field public static final int RADIUS_AUTO = -1; // 0xffffffff
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
-->
|
||||
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="?attr/colorControlHighlight"
|
||||
android:rippleStyle="?attr/rippleStyle">
|
||||
android:color="?attr/colorControlHighlight">
|
||||
<item android:id="@id/mask"
|
||||
android:drawable="@drawable/btn_default_mtrl_shape" />
|
||||
</ripple>
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
android:insetTop="@dimen/button_inset_vertical_material"
|
||||
android:insetRight="@dimen/button_inset_horizontal_material"
|
||||
android:insetBottom="@dimen/button_inset_vertical_material">
|
||||
<ripple android:color="?attr/colorControlHighlight"
|
||||
android:rippleStyle="?attr/rippleStyle">
|
||||
<ripple android:color="?attr/colorControlHighlight">
|
||||
<item>
|
||||
<shape android:shape="rectangle"
|
||||
android:tint="@color/btn_colored_background_material">
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
-->
|
||||
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="?attr/colorControlHighlight"
|
||||
android:rippleStyle="?attr/rippleStyle">
|
||||
android:color="?attr/colorControlHighlight">
|
||||
<item android:drawable="@drawable/btn_default_mtrl_shape" />
|
||||
</ripple>
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
android:insetBottom="@dimen/button_inset_vertical_material">
|
||||
<layer-list android:paddingMode="stack">
|
||||
<item>
|
||||
<ripple android:color="?attr/colorControlHighlight"
|
||||
android:rippleStyle="?attr/rippleStyle">
|
||||
<ripple android:color="?attr/colorControlHighlight">
|
||||
<item>
|
||||
<shape android:shape="rectangle"
|
||||
android:tint="?attr/colorButtonNormal">
|
||||
|
||||
@@ -1176,6 +1176,9 @@
|
||||
<!-- Alternative color applied to surfaces on top of colorBackground. @hide -->
|
||||
<attr name="colorSurfaceHeader" format="color" />
|
||||
|
||||
<!-- Color applied to effects. -->
|
||||
<attr name="effectColor" format="color" />
|
||||
|
||||
<!-- The type of the edge effect. The default is glow. -->
|
||||
<attr name="edgeEffectType">
|
||||
<!-- Use a colored glow at the edge. -->
|
||||
@@ -6540,13 +6543,8 @@
|
||||
<!-- The radius of the ripple when fully expanded. By default, the
|
||||
radius is computed based on the size of the ripple's container. -->
|
||||
<attr name="radius" />
|
||||
<!-- The style of the ripple drawable is solid by default -->
|
||||
<attr name="rippleStyle">
|
||||
<!-- Solid is the default style -->
|
||||
<enum name="solid" value="0" />
|
||||
<!-- Patterned style-->
|
||||
<enum name="patterned" value="1" />
|
||||
</attr>
|
||||
<!-- Secondary color of the ripple effect. -->
|
||||
<attr name="effectColor" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="ScaleDrawable">
|
||||
|
||||
@@ -3099,6 +3099,7 @@
|
||||
<!-- @hide @SystemApi -->
|
||||
<public name="throttleDurationMillis" />
|
||||
<public name="showInInputMethodPicker" />
|
||||
<public name="effectColor" />
|
||||
</staging-public-group>
|
||||
|
||||
<staging-public-group type="drawable" first-id="0x010800b5">
|
||||
|
||||
@@ -234,9 +234,6 @@ easier.
|
||||
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
|
||||
<item name="colorForeground">@color/foreground_device_default_dark</item>
|
||||
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
|
||||
|
||||
<!-- Ripple style-->
|
||||
<item name="rippleStyle">solid</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" />
|
||||
|
||||
@@ -150,6 +150,7 @@ public class RippleDrawable extends LayerDrawable {
|
||||
/** The maximum number of ripples supported. */
|
||||
private static final int MAX_RIPPLES = 10;
|
||||
private static final LinearInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
|
||||
private static final int DEFAULT_EFFECT_COLOR = 0x80ffffff;
|
||||
/** Temporary flag for teamfood. **/
|
||||
private static final boolean FORCE_PATTERNED_STYLE = true;
|
||||
|
||||
@@ -465,11 +466,36 @@ public class RippleDrawable extends LayerDrawable {
|
||||
*
|
||||
* @attr ref android.R.styleable#RippleDrawable_color
|
||||
*/
|
||||
public void setColor(ColorStateList color) {
|
||||
public void setColor(@NonNull ColorStateList color) {
|
||||
if (color == null) {
|
||||
throw new IllegalArgumentException("color cannot be null");
|
||||
}
|
||||
mState.mColor = color;
|
||||
invalidateSelf(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ripple effect color.
|
||||
*
|
||||
* @param color Ripple color as a color state list.
|
||||
*
|
||||
* @attr ref android.R.styleable#RippleDrawable_effectColor
|
||||
*/
|
||||
public void setEffectColor(@NonNull ColorStateList color) {
|
||||
if (color == null) {
|
||||
throw new IllegalArgumentException("color cannot be null");
|
||||
}
|
||||
mState.mEffectColor = color;
|
||||
invalidateSelf(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ripple effect color as a color state list.
|
||||
*/
|
||||
public @NonNull ColorStateList getEffectColor() {
|
||||
return mState.mEffectColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the radius in pixels of the fully expanded ripple.
|
||||
*
|
||||
@@ -561,13 +587,14 @@ public class RippleDrawable extends LayerDrawable {
|
||||
mState.mColor = color;
|
||||
}
|
||||
|
||||
final ColorStateList effectColor =
|
||||
a.getColorStateList(R.styleable.RippleDrawable_effectColor);
|
||||
if (effectColor != null) {
|
||||
mState.mEffectColor = effectColor;
|
||||
}
|
||||
|
||||
mState.mMaxRadius = a.getDimensionPixelSize(
|
||||
R.styleable.RippleDrawable_radius, mState.mMaxRadius);
|
||||
|
||||
if (!FORCE_PATTERNED_STYLE) {
|
||||
mState.mRippleStyle = a.getInteger(R.styleable.RippleDrawable_rippleStyle,
|
||||
mState.mRippleStyle);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException {
|
||||
@@ -942,10 +969,11 @@ public class RippleDrawable extends LayerDrawable {
|
||||
float radius = getComputedRadius();
|
||||
RippleAnimationSession.AnimationProperties<Float, Paint> properties;
|
||||
RippleShader shader = new RippleShader();
|
||||
int color = mMaskColorFilter == null
|
||||
final int color = mMaskColorFilter == null
|
||||
? mState.mColor.getColorForState(getState(), Color.BLACK)
|
||||
: mMaskColorFilter.getColor();
|
||||
shader.setColor(color);
|
||||
final int effectColor = mState.mEffectColor.getColorForState(getState(), Color.MAGENTA);
|
||||
shader.setColor(color, effectColor);
|
||||
shader.setOrigin(cx, cy);
|
||||
shader.setTouch(x, y);
|
||||
shader.setResolution(w, h, mState.mDensity);
|
||||
@@ -1266,33 +1294,6 @@ public class RippleDrawable extends LayerDrawable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visual style of the ripple.
|
||||
*
|
||||
* @see #STYLE_SOLID
|
||||
* @see #STYLE_PATTERNED
|
||||
*
|
||||
* @param style The style of the ripple
|
||||
* @hide
|
||||
*/
|
||||
public void setRippleStyle(@RippleStyle int style) throws IllegalArgumentException {
|
||||
if (style == STYLE_SOLID || style == STYLE_PATTERNED) {
|
||||
mState.mRippleStyle = style;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid style value " + style);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current ripple style
|
||||
* @return Ripple style
|
||||
* @hide
|
||||
*/
|
||||
public @RippleStyle int getRippleStyle() {
|
||||
return mState.mRippleStyle;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
RippleState createConstantState(LayerState state, Resources res) {
|
||||
return new RippleState(state, this, res);
|
||||
@@ -1302,6 +1303,7 @@ public class RippleDrawable extends LayerDrawable {
|
||||
int[] mTouchThemeAttrs;
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
ColorStateList mColor = ColorStateList.valueOf(Color.MAGENTA);
|
||||
ColorStateList mEffectColor = ColorStateList.valueOf(DEFAULT_EFFECT_COLOR);
|
||||
int mMaxRadius = RADIUS_AUTO;
|
||||
int mRippleStyle = FORCE_PATTERNED_STYLE ? STYLE_PATTERNED : STYLE_SOLID;
|
||||
|
||||
@@ -1314,6 +1316,7 @@ public class RippleDrawable extends LayerDrawable {
|
||||
mColor = origs.mColor;
|
||||
mMaxRadius = origs.mMaxRadius;
|
||||
mRippleStyle = origs.mRippleStyle;
|
||||
mEffectColor = origs.mEffectColor;
|
||||
|
||||
if (origs.mDensity != mDensity) {
|
||||
applyDensityScaling(orig.mDensity, mDensity);
|
||||
|
||||
@@ -39,6 +39,7 @@ final class RippleShader extends RuntimeShader {
|
||||
+ "uniform vec2 in_tRotation2;\n"
|
||||
+ "uniform vec2 in_tRotation3;\n"
|
||||
+ "uniform vec4 in_color;\n"
|
||||
+ "uniform vec4 in_sparkleColor;\n"
|
||||
+ "uniform shader in_shader;\n";
|
||||
private static final String SHADER_LIB =
|
||||
"float triangleNoise(vec2 n) {\n"
|
||||
@@ -48,7 +49,6 @@ final class RippleShader extends RuntimeShader {
|
||||
+ " return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;\n"
|
||||
+ "}"
|
||||
+ "const float PI = 3.1415926535897932384626;\n"
|
||||
+ "const float SPARKLE_OPACITY = 0.75;\n"
|
||||
+ "\n"
|
||||
+ "float sparkles(vec2 uv, float t) {\n"
|
||||
+ " float n = triangleNoise(uv);\n"
|
||||
@@ -60,7 +60,7 @@ final class RippleShader extends RuntimeShader {
|
||||
+ " o *= abs(sin(PI * o * (t + 0.55 * i)));\n"
|
||||
+ " s += o;\n"
|
||||
+ " }\n"
|
||||
+ " return saturate(s) * SPARKLE_OPACITY;\n"
|
||||
+ " return saturate(s) * in_sparkleColor.a;\n"
|
||||
+ "}\n"
|
||||
+ "float softCircle(vec2 uv, vec2 xy, float radius, float blur) {\n"
|
||||
+ " float blurHalf = blur * 0.5;\n"
|
||||
@@ -116,7 +116,7 @@ final class RippleShader extends RuntimeShader {
|
||||
+ " vec4 circle = in_color * (softCircle(p, center, in_maxRadius "
|
||||
+ " * scaleIn, 0.2) * fade);\n"
|
||||
+ " float mask = in_hasMask == 1. ? sample(in_shader).a > 0. ? 1. : 0. : 1.;\n"
|
||||
+ " return mix(circle, vec4(sparkle), sparkle) * mask;\n"
|
||||
+ " return mix(circle, in_sparkleColor, sparkle) * mask;\n"
|
||||
+ "}";
|
||||
private static final String SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN;
|
||||
private static final double PI_ROTATE_RIGHT = Math.PI * 0.0078125;
|
||||
@@ -197,10 +197,13 @@ final class RippleShader extends RuntimeShader {
|
||||
/**
|
||||
* Color of the circle that's under the sparkles. Sparkles will always be white.
|
||||
*/
|
||||
public void setColor(@ColorInt int colorIn) {
|
||||
Color color = Color.valueOf(colorIn);
|
||||
this.setUniform("in_color", new float[] {color.red(),
|
||||
public void setColor(@ColorInt int colorInt, @ColorInt int sparkleColorInt) {
|
||||
Color color = Color.valueOf(colorInt);
|
||||
Color sparkleColor = Color.valueOf(sparkleColorInt);
|
||||
setUniform("in_color", new float[] {color.red(),
|
||||
color.green(), color.blue(), color.alpha()});
|
||||
setUniform("in_sparkleColor", new float[] {sparkleColor.red(),
|
||||
sparkleColor.green(), sparkleColor.blue(), sparkleColor.alpha()});
|
||||
}
|
||||
|
||||
public void setResolution(float w, float h, int density) {
|
||||
|
||||
Reference in New Issue
Block a user