【问题标题】:Programmatically tint a Support Vector以编程方式为支持向量着色
【发布时间】:2016-08-22 05:10:12
【问题描述】:

Android Studio 2.1 版,gradle 2.1.0 版,如果您发现任何误解,请纠正我:)

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

我已经阅读了几篇关于这些变化的相关帖子: 23.2.0 announcement and changes

从 Android 支持库 23.3.0 开始,支持矢量可绘制对象只能通过 app:srcCompat 或 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);

这会在棒棒糖之前引发相同的错误。

但是,如果我删除 vectorDrawables.useSupportLibrary = true,正如 by Ian Lake here 指出的那样,为了让构建工具为预棒棒糖设备自动生成 png,png 不会在预棒棒糖上着色,所以我又回到了原点。

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

所以 23.3.0 的情况似乎是:

  • Post-Lollipop:srcsrcCompat 接受向量,只有 src 可以 从视图中检索为用于以编程方式着色的可绘制对象。 使用 getDrawable 可以在代码中引用向量,并且它们 可以染色。

  • Pre-Lollipop:srcCompat 只能接受向量,无法检索 从着色的角度以编程方式。 setImageResource可以 接受向量,但前提是vectorDrawables.useSupportLibrary = false,并且着色不起作用。类似地在代码中引用向量不是 可能,除非vectorDrawables.useSupportLibrary = false 和着色 不起作用。

使用 pngs 处理所有版本:

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

附录:

这种技术也适用于棒棒糖后,但与棒棒糖前的其他技术一样,我得到了可绘制对象,但没有着色:

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

解决方案:

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

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

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

【问题讨论】:

  • 如果您使用 Vector Compat 库来创建您的 drawble,它是否有效?即 VectorDrawableCompat.create(getResources(),R.drawable.ic_action_add,null)
  • 我已经更新了我的答案,看起来这是另一种技术(!)来做同样的事情,但着色它在 pre-L 上不起作用
  • 这不是另一种技术,这就是 VectorDrawableCompat 的创建方式,如果您阅读 DrawableCompat 文档,您会发现 this 可以正常工作
  • 好的,谢谢!我想做更多的测试,但对我来说,关键的缺失组件似乎是对 wrap() 可绘制对象的调用。这似乎是 pre-L 所必需的,以及对create 的调用,而不是仅仅加载可绘制对象或通过它的视图引用它。我实际上已经通过 wrap 调用尝试了这两种方法,但不是 create!如果您想发布一个告诉我包装它的答案,我会标记它:)

标签: android android-appcompat android-vectordrawable


【解决方案1】:

首先你应该使用VectorDrawableCompat#create,一旦你有你的Drawable,你必须打电话给DrawableCompat#wrap

可能包裹drawable,以便它可以用于着色 不同的 API 级别,通过此类中的着色方法。

所以你的代码看起来像这样:

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

【讨论】:

  • 我在另一个地方用过同样的,它工作正常,但这次它不工作,我不知道为什么
  • ImageView imageView = new ImageView(new ContextThemeWrapper(parent.getContext(), R.style.CalendarCell_CalendarDate)); imageView.setDuplicateParentStateEnabled(true); parent.addView(imageView, new FrameLayout.LayoutParams(50, 50, CENTER_VERTICAL)); parent.setDayOfMonthTextView(imageView);
  • Drawable d = VectorDrawableCompat.create(getResources(), R.drawable.ic_circle, null); d = DrawableCompat.wrap(d); DrawableCompat.setTint(d, dailyLim.intValue()); cellView.getDayOfMonthImageView().setImageDrawable(d);
  • 什么是dailyLim.intValue()?测试用Color.RED
  • 让我试试这个
【解决方案2】:

你可以使用ImageView的setColorFilter方法:

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

【讨论】:

  • 目前这似乎是最好的解决方案,虽然我对此并不满意!
【解决方案3】:

使用 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)

【讨论】:

    猜你喜欢
    • 2014-01-07
    • 1970-01-01
    • 2014-04-01
    • 2016-12-18
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多