以编程方式为支持向量着色

Programmatically tint a Support Vector

AndroidStudio 2.1版本,gradle2.1.0版本,如有错误请指正:)

我对支持库 23.3.0 中的支持向量感到困惑。具体来说,我想做的是以编程方式为图像按钮着色,其 src 被定义为可绘制的矢量。据我所知,这在棒棒糖之前是不可能的。

我已阅读几篇有关更改的相关 post: 23.2.0 announcement and changes:

As of Android Support Library 23.3.0, support vector drawables can only be loaded via app:srcCompat or setImageResource().

以上是否意味着矢量 xml 只能通过 srcCompat 或 setImageResource() 在 Lollipop 之前使用,因此 不能动态着色

这是我的基本图像按钮:

<ImageButton
    android:id="@+id/nav_header_exit_community_button"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:layout_alignParentTop="true"
    android:layout_alignParentRight="true"
    android:background="@null"/>

仅适用于 Lollipop 及更高版本:

    Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);
    DrawableCompat.setTint(bg, headerTitleColor);
    exitButton.setImageDrawable(bg);

尝试这个预棒棒糖抛出: android.content.res.Resources$NotFoundException: File res/drawable/ic_exit_to_app_24dp.xml from drawable resource ID #0x7f0200bf

也仅适用于 Lollipop 及更高版本

    Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);
    DrawableCompat.setTint(bg, headerTitleColor);
    exitButton.setImageResource(R.drawable.ic_exit_to_app_24dp);

这会在 pre-Lollipop 上引发相同的错误。

但是,如果我按照 的指示删除 vectorDrawables.useSupportLibrary = true,目的是让构建工具为 Lollipop 之前的设备自动生成 png,png 不会在棒棒糖前染色,所以我回到原点。

我也尝试通过 srcCompat 指定向量并以编程方式检索它,但我认为我无法实现这一点,即使它适用于 post-Lollipop 如果向量是使用 src 指定的。

因此 23.3.0 的情况似乎是:

使用 png 处理所有版本:

   Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_nav_exit_community);
   DrawableCompat.setTint(bg, headerTitleColor);
   exitButton.setImageDrawable(bg);

附录:

此技术也适用于 post-Lollipop,但与其他 Lollipop 之前的技术一样,我得到了可绘制对象,但没有着色:

    Drawable bg = VectorDrawableCompat.create(a.getResources(), R.drawable.ic_exit_to_app_24dp, null);
    DrawableCompat.setTint(bg, headerTitleColor);
    exitButton.setImageDrawable(bg);

解决方案种类:

感谢 的回答,到目前为止,我能想出的唯一万无一失的方法是在支持向量上设置一个滤色器——这意味着 DrawableCompat.setTint() 函数是如果有问题的可绘制对象是支持向量,那么对我来说似乎不起作用。我不确定这是一个合法的错误、预期的行为还是我只是做错了什么!

这是我目前要使用的解决方案:

    Drawable bg;
    if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        bg = VectorDrawableCompat.create(a.getResources(), R.drawable.ic_exit_to_app_24dp, null);
        exitButton.setColorFilter(headerTitleColor, PorterDuff.Mode.MULTIPLY);
    }
    else {
        bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);
        DrawableCompat.setTint(bg, headerTitleColor);
    }
    exitButton.setImageDrawable(bg);

可以使用ImageView的setColorFilter方法:

imageView.setColorFilter(headerTitleColor, android.graphics.PorterDuff.Mode.MULTIPLY);

首先你应该使用 VectorDrawableCompat#create,一旦你有你的 Drawable 你必须调用 DrawableCompat#wrap:

Potentially wrap drawable so that it may be used for tinting across the different API levels, via the tinting methods in this class.

因此您的代码将如下所示:

ImageView iv = ....
Drawable d = VectorDrawableCompat.create(getResources(), R.drawable.ic_exit_to_app_24dp, null);
d = DrawableCompat.wrap(d);
DrawableCompat.setTint(d, headerTitleColor);
iv.setImageDrawable(d);

Kotlin 的另一个便捷解决方案:

fun Context.drawableWithColor(@DrawableRes drawableRes: Int, @ColorInt color: Int): Drawable? {
    val pic = ContextCompat.getDrawable(this, drawableRes)
    pic?.setColorFilter(color, PorterDuff.Mode.SRC_IN)
    return pic
}

使用很简单:

val drawable = context.drawableWithColor(R.drawable.your_awesome_drawable, Color.BLUE)