Android:使用 DrawableCompat 进行着色
Posted
技术标签:
【中文标题】Android:使用 DrawableCompat 进行着色【英文标题】:Android: Tint using DrawableCompat 【发布时间】:2014-11-06 19:55:18 【问题描述】:我正在尝试为 android API 级别 21 之前的图像着色。我已成功使用以下方法着色项目:
<android:tint="@color/red"/>
但是,我似乎无法通过 ImageView 上的代码弄清楚如何做到这一点:
Drawable iconDrawable = this.mContext.getResources().getDrawable(R.drawable.somedrawable);
DrawableCompat.setTint(iconDrawable, this.mContext.getResources().getColor(R.color.red));
imageView.setImageDrawable(iconDrawable);
我尝试设置 TintMode,但这似乎没有什么不同。我是否错误地使用了 v4 兼容类 DrawableCompat?
【问题讨论】:
我设法通过应用 ColorFilter 来获得我想要的效果,使用模式 SRC_IN 我相信这意味着它只是将 alpha 通道乘以颜色 - 这就是我想要的色调: setColorFilter(this.mContext.getResources().getColor(R.color.red), PorterDuff.Mode.SRC_IN) 【参考方案1】:如果有人需要在不影响其他可绘制对象的情况下使用DrawableCompat
的着色,以下是使用mutate()
的方法:
Drawable drawable = getResources().getDrawable(R.drawable.some_drawable);
Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
wrappedDrawable = wrappedDrawable.mutate();
DrawableCompat.setTint(wrappedDrawable, getResources().getColor(R.color.white));
可以简化为:
Drawable drawable = getResources().getDrawable(R.drawable.some_drawable);
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable.mutate(), getResources().getColor(R.color.white));
【讨论】:
mutate() 是正确的方法。没有它,您将在全局范围内为整个应用程序着色。引用javadoc:“一个可变的drawable保证不与任何其他drawable共享其状态。当您需要修改从资源加载的drawable的属性时,这特别有用。默认情况下,从同一资源加载的所有drawable实例共享一个公共状态;如果您修改一个实例的状态,所有其他实例将收到相同的修改。" 适用于 4.1 及更高版本(API 16 及更高版本)。使用最新的支持库 (23.1.1) 进行测试。至少在 4.1 中需要突变。适用于 21 和 23。 如果需要使用选择器,请改用DrawableCompat.setTintList()
。
如果你使用这个,drawable tint 会全局改变,不会恢复。我使用的 lib 之一使用此代码,它会在每个活动中全局更改我的可绘制对象的颜色 @Brett 你错了
getResources().getColor(int res)
- 已弃用,仅使用上下文即可获得颜色 ContextCompat.getColor(context, R.color.my_color);
【参考方案2】:
DrawableCompat
以前不支持着色。
从支持库 22.1 开始,您可以这样做,但您需要这样做:
Drawable normalDrawable = getResources().getDrawable(R.drawable.drawable_to_tint);
Drawable wrapDrawable = DrawableCompat.wrap(normalDrawable);
DrawableCompat.setTint(wrapDrawable, getResources().getColor(R.color.colorPrimaryLight));
【讨论】:
我想知道是否有人可以使用mutate()
drawable 完成这项工作
@Zyoo 我很确定你不再需要它了,但我只是在这里使用DrawableCompat
's tinting with mutate()
发布了一个答案。想你还是想看看:)
这适用于 API 级别 23 和 API 级别 19,但不适用于 API 级别 21。
我必须添加一个 drawable.invalidateSelf() 才能让它工作,但除此之外,没有问题【参考方案3】:
跨平台着色的最简单方法(如果您不需要 ColorStateList)是:
drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
在应用过滤器之前不要忘记改变 Drawable。
【讨论】:
不知道为什么有人不赞成这个,但这段代码实际上是 AppCompat 为以前的 Android 版本所做的。 AppCompat API 执行此操作非常冗长,因此与此代码相比,我认为使用它不会有太多收获。DrawableComapat.setTint(_, _)
在我尝试在 prelollipop 中多次执行时遇到了一些问题。我得到了这个作为解决方案。谢谢【参考方案4】:
这里的答案不适用于棒棒糖之前的设备 (SupportLib 23.4.0),但我发布了适用于 API 17 及更高版本的解决方法:https://***.com/a/37434219/2170109
以下代码已经过测试,正在 API 17、19、21、22、23 和 N Preview 3 上运行:
// https://***.com/a/30928051/2170109
Drawable drawable = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.vector));
image.setImageDrawable(drawable);
/*
* need to use the filter | https://***.com/a/30880522/2170109
* (even if compat should use it for pre-API21-devices | https://***.com/a/27812472/2170109)
*/
int color = ContextCompat.getColor(context, R.color.yourcolor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
DrawableCompat.setTint(drawable, color);
else
drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
【讨论】:
@hardysim DrawableCompat 不是已经为我们执行了这项检查吗?因此名称为“...Compat”。类文档:/** * 用于访问 @link android.graphics.drawable.Drawable 中的功能的助手 * 在 API 级别 4 之后以向后兼容的方式引入。 */ @superuserdo 正如我在另一篇文章 (***.com/a/37434219/2170109) 中提到的那样,我很难让它在所有 API 上工作——即使 Compat 类声称是万能的解决方案.【参考方案5】:如果您查看 DrawableCompat 的源代码,您将看到任何版本 the method does nothing。
DrawableCompat 的想法似乎只是不会在旧版本上崩溃,而不是实际提供该功能。
【讨论】:
这是 DrawableCompat 方法的一个巨大限制,似乎适用于 > 22.1 的应用兼容版本。 如果你真正遵循使用哪个类,你会看到DrawableWrapper
使用滤色器实现色调。
@JakeWharton 问题仍然存在,你能发布如何正确地做到这一点吗,这篇文章中没有一个答案完全有效,或者太模糊了。【参考方案6】:
使用支持库 22.1,您可以使用 DrawableCompat 为可绘制对象着色。
DrawableCompat.wrap(Drawable) 和 setTint()、setTintList() 和 setTintMode() 将正常工作:无需创建和维护单独的可绘制对象,仅支持多种颜色!
【讨论】:
【参考方案7】:我将在这里分享我的解决方案,因为它可能会为某人节省一些时间。
我有一个ImageView
使用矢量可绘制作为其源可绘制(实际上,它是支持矢量可绘制from Android 支持库 23.3)。所以,首先我把它包装成这样:
mImageView.setImageDrawable(DrawableCompat.wrap(mImageView.getDrawable()));
然后我尝试像这样对其应用色调:
DrawableCompat.setTint(
mImageView.getDrawable(),
getResources().getColor(R.color.main_color)
);
运气不好。
我尝试在包装的可绘制对象以及原始可绘制对象上调用mutate()
- 仍然没有运气。 invalidate()
调用 mImageView
成功了。
【讨论】:
你没有使用 AppCompatImageView 吗?【参考方案8】:为视图设置 tint 和 drawable 并使其向后兼容,同时使用 kotlin 支持当前的上下文主题,而不检查当前的 SDK 版本并避免不推荐使用的方法:
imageView.setImageDrawable(
ContextCompat.getDrawable(context, R.drawable.somedrawable).apply
setTint(ContextCompat.getColor(context, R.color.red))
)
【讨论】:
以上是关于Android:使用 DrawableCompat 进行着色的主要内容,如果未能解决你的问题,请参考以下文章