如何在 Android 5.0 Lollipop 的代码(不是 xml)中以编程方式使用 RippleDrawable?

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

我的涟漪代码如下:

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:colorControlHighlight">
    <item android:id="@+id/rip">

        <shape android:shape="oval">
            <solid android:color="?android:colorAccent"/>
        </shape>
    </item>
</ripple>

现在我想让用户可以选择自己的颜色,所以我需要以编程方式创建波纹。
我发现 this,我认为这是正确的方法,但我不知道如何处理。

这里会用到涟漪:

<ImageButton
    android:id="@+id/add_button"
    android:layout_width="@dimen/diameter"
    android:layout_height="@dimen/diameter"
    android:layout_gravity="end|bottom"
    android:layout_marginBottom="@dimen/add_button_margin"
    android:layout_marginEnd="@dimen/add_button_margin"
    android:layout_alignParentBottom="true"
    android:layout_alignParentEnd="true"
    android:src="@drawable/ic_action_add_person"
    android:tint="@android:color/white"
    android:background="@drawable/oval_ripple"
    android:elevation="@dimen/elevation_low"
    android:stateListAnimator="@anim/button_elevation"
    android:contentDescription="Neuer Spieler" />

我需要将背景设置为 RippleDrawable,如下所示:

addButton.setBackground(ripple);

我就是这样实现的。

请注意,这仅是 Api 21+,因此如果您支持较低版本,则必须回退到普通 Drawable。

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);
}

编辑: 我对此进行了更多修改,发现 ColorStateList 不需要像上述解决方案那样复杂。我已将其简化为以下代码段。 (上面代码块中的其他所有内容都是相同的。我只更改了 ColorStateList 的创建。)我将保留上面的代码块作为原始代码块,以防此方法对某些人不起作用。

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;
}

您可以使用 view.setDrawable.
获取可绘制对象并应用于任何视图 对于 Lollipop+ 设备,你会得到波纹,否则它会改变视图的颜色。

基本上,您需要创建一个新的 RippleDrawable 对象。对于 Lollipop 之前的设备,您需要一个 StateListDrawable(正如其他人已经建议的那样)。我写了一个有点足智多谋的 GIST,其中包含一些与 Drawables 和着色相关的有用方法: https://gist.github.com/milosmns/6566ca9e3b756d922aa5

您很可能希望使用该单例中的 #getBackgroundDrawable()

您可以将其指定为前台,在 Kotlin 中:

view.foreground = ContextCompat.getDrawable(context, R.drawable.rippleRes)