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

Posted

技术标签:

【中文标题】如何在带有 Android 5.0 Lollipop 的代码(不是 xml)中以编程方式使用 RippleDrawable?【英文标题】:How to use RippleDrawable programmatically in code (not xml) with Android 5.0 Lollipop? 【发布时间】:2015-03-03 11:35:45 【问题描述】:

我的波纹有以下代码:

<?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_
    android:layout_
    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);

【问题讨论】:

你在哪里使用你的xml资源? @pskink 我编辑了第一篇文章 :) 那么创建一个新的RippleDrawable有什么问题? 我不知道如何使用它。 可绘制波纹 = 新 RippleDrawable(...) 【参考方案1】:

这就是我能够做到这一点的方式。

请注意,这只是 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 不需要像上述解决方案那样复杂。我已将其简化为以下 sn-p。 (上面代码块中的其他所有内容都是一样的。我只是更改了 ColorStateList 创建。)我将上面的代码块保留为原始代码块,以防此方法不适用于某人。

new ColorStateList(
    new int[][]
        
            new int[]
        ,
    new int[]
        
            pressedColor
        
);

【讨论】:

非常感谢您的回答 :) (不能给您点赞,没有足够的声誉)。 没问题;弄清楚这很痛苦,所以我很乐意分享。 :) 它对你有用吗?我对其进行了更多修改,并了解到我可以大大简化 ColorStateList 并获得相同的结果,因此我编辑了我的答案以包含它。 你也可以使用ColorStateList.valueOf(rippleColor); 请注意,此解决方案添加了一个掩码。所以如果你有,假设一个蓝色按钮并将pressedColor设置为黄色,那么波纹将是紫色的。 @JoaquinIurchuk 你如何解决它? rippleDrawable.setId(index, android.R.id.mask) 没用。【参考方案2】:
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+ 设备,您会看到波纹,否则它会改变视图的颜色。

【讨论】:

这很好。我认为,一个缺点是,当应用在棒棒糖前设备上时,它可能会失去圆角,因为StateListDrawable 中的ColorDrawables 没有形状。我们可以提供彩色的ShapeDrawable 来保持形状。但也许这会开始变得有点沉重。在这种情况下,另一种解决方案是使用“setColor”方法创建自定义“ColorStateDrawable”,避免您重新实例化 StateListDrawable 所需的所有对象。 在这里附近找到了一些东西:github.com/gabrielemariotti/colorpickercollection/blob/master/…【参考方案3】:

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

您很可能希望从该单身人士中使用#getBackgroundDrawable()

【讨论】:

您可能需要考虑从链接发布代码的相关部分。 它非常庞大,我不确定在这里发布一个包含十个 50 行方法的链是否相关。这是我的主旨,所以它被故意保持活力:)【参考方案4】:

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

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

【讨论】:

以上是关于如何在带有 Android 5.0 Lollipop 的代码(不是 xml)中以编程方式使用 RippleDrawable?的主要内容,如果未能解决你的问题,请参考以下文章

Android 5.0 Lollipop 中的 ActionMode ActionBar 样式(带有 AppCompat)

Gulp-sass 5.0 如何使用带有 import() 而不是 require() 的编译器?

如何在 Camera2 API Android 5.0 中获取单个预览帧?

sh 如何导出领域数据库,在Android 5.0+上工作

Android Studio - 如何在 webview Lollipop 中上传文件 (Android 5.0)

应用程序如何检测状态栏颜色(Android 5.0 Lollipop)?