setColorFilter 似乎不适用于 kitkat
setColorFilter doesn't seem to work on kitkat
我正在尝试使用 setColorFilter
为图形着色。以下代码似乎在棒棒糖上运行良好,但似乎对 kitkat 没有影响,图标以其原始颜色呈现:
Drawable icon = ContextCompat.getDrawable(context, R.drawable.ic_chat_button).mutate();
icon.setColorFilter(context.getResources().getColor(R.color.control_tint_color), PorterDuff.Mode.SRC_ATOP);
icon.invalidateSelf();
mutate
和 invalidateSelf
调用似乎对这里的问题没有任何影响,只是将它们作为示例,作为试图弄清楚发生了什么的部分示例.
FWIW,我将 drawable 用作 StateListDrawable
中 LayerDrawable
的一部分,它被用作按钮的背景或 ImageView
的 drawable无论哪种方式,结果都是一致的(即,在 kitkat 上是错误的)。我还尝试再次将可绘制图标直接放入 StateListDrawable
中,但行为没有任何变化。在所有情况下,它都适用于棒棒糖,但不适用于 kitkat。
作为实验,我从 StateListDrawable
中取出了有色 Drawable
而不是 LayerDrawable
并且它按预期工作。显然,KitKat 对 StateListDrawable
的实现存在一些缺陷,导致其无法正常工作,但已在更高版本中修复。
最终,问题似乎是 KitKat 不支持在 Drawable
上使用 ColorFilter
(或隐含的 alpha),而 Drawable
又会在 StateListDrawable
.我的解决方案是使用相同的代码来构建复杂的 Drawable
,然后将其呈现为简单的 BitMapDrawable
:
static Drawable createDrawable(Context context, int color, boolean disabled) {
OvalShape oShape = new OvalShape();
ShapeDrawable background = new ShapeDrawable(oShape);
background.getPaint().setColor(color);
ShapeDrawable shader = new ShapeDrawable(oShape);
shader.setShaderFactory(new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new LinearGradient(0, 0, 0, height,
new int[]{
Color.WHITE,
Color.GRAY,
Color.DKGRAY,
Color.BLACK
}, null, Shader.TileMode.REPEAT);
}
});
Drawable icon = ContextCompat.getDrawable(context, R.drawable.ic_chat_button).mutate();
icon.setColorFilter(context.getResources().getColor(R.color.control_tint_color), PorterDuff.Mode.SRC_IN);
Drawable layer = new LayerDrawable(new Drawable[]{ shader, background, icon });
layer.setAlpha(disabled ? 128 : 255);
// Note that on KitKat, setting a ColorFilter on a Drawable contained in a StateListDrawable
// apparently doesn't work, although it does on later versions, so we have to render the colored
// bitmap into a BitmapDrawable and then put that into the StateListDrawable
Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layer.setBounds(0, 0, layer.getIntrinsicWidth(), layer.getIntrinsicHeight());
layer.draw(canvas);
return new BitmapDrawable(context.getResources(), bitmap);
}
而不是将着色附加到 "disabled" 状态(如在接受的答案中),我发现通过专注于重新着色并让我的用法利用如何包含现在着色的图像,答案更简单在 StateListDrawable
。 (仅供参考,我尝试从我正在使用的 Xamarin C# 进行翻译,但下面的代码可能无法正确编译为 Java)
static Drawable recolorDrawable(Drawable icon, int toColor)
{
Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas myCanvas = new Canvas(bitmap);
icon.setColorFilter(toColor, PorterDuff.Mode.SRC_IN);
icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
icon.draw(myCanvas);
return new BitmapDrawable(context.getResources(), bitmap);
}
最后,公平地说,我对 Android 开发很陌生,感谢他在简化之前展示了我需要的部分。
我正在尝试使用 setColorFilter
为图形着色。以下代码似乎在棒棒糖上运行良好,但似乎对 kitkat 没有影响,图标以其原始颜色呈现:
Drawable icon = ContextCompat.getDrawable(context, R.drawable.ic_chat_button).mutate();
icon.setColorFilter(context.getResources().getColor(R.color.control_tint_color), PorterDuff.Mode.SRC_ATOP);
icon.invalidateSelf();
mutate
和 invalidateSelf
调用似乎对这里的问题没有任何影响,只是将它们作为示例,作为试图弄清楚发生了什么的部分示例.
FWIW,我将 drawable 用作 StateListDrawable
中 LayerDrawable
的一部分,它被用作按钮的背景或 ImageView
的 drawable无论哪种方式,结果都是一致的(即,在 kitkat 上是错误的)。我还尝试再次将可绘制图标直接放入 StateListDrawable
中,但行为没有任何变化。在所有情况下,它都适用于棒棒糖,但不适用于 kitkat。
作为实验,我从 StateListDrawable
中取出了有色 Drawable
而不是 LayerDrawable
并且它按预期工作。显然,KitKat 对 StateListDrawable
的实现存在一些缺陷,导致其无法正常工作,但已在更高版本中修复。
最终,问题似乎是 KitKat 不支持在 Drawable
上使用 ColorFilter
(或隐含的 alpha),而 Drawable
又会在 StateListDrawable
.我的解决方案是使用相同的代码来构建复杂的 Drawable
,然后将其呈现为简单的 BitMapDrawable
:
static Drawable createDrawable(Context context, int color, boolean disabled) {
OvalShape oShape = new OvalShape();
ShapeDrawable background = new ShapeDrawable(oShape);
background.getPaint().setColor(color);
ShapeDrawable shader = new ShapeDrawable(oShape);
shader.setShaderFactory(new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new LinearGradient(0, 0, 0, height,
new int[]{
Color.WHITE,
Color.GRAY,
Color.DKGRAY,
Color.BLACK
}, null, Shader.TileMode.REPEAT);
}
});
Drawable icon = ContextCompat.getDrawable(context, R.drawable.ic_chat_button).mutate();
icon.setColorFilter(context.getResources().getColor(R.color.control_tint_color), PorterDuff.Mode.SRC_IN);
Drawable layer = new LayerDrawable(new Drawable[]{ shader, background, icon });
layer.setAlpha(disabled ? 128 : 255);
// Note that on KitKat, setting a ColorFilter on a Drawable contained in a StateListDrawable
// apparently doesn't work, although it does on later versions, so we have to render the colored
// bitmap into a BitmapDrawable and then put that into the StateListDrawable
Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layer.setBounds(0, 0, layer.getIntrinsicWidth(), layer.getIntrinsicHeight());
layer.draw(canvas);
return new BitmapDrawable(context.getResources(), bitmap);
}
而不是将着色附加到 "disabled" 状态(如在接受的答案中),我发现通过专注于重新着色并让我的用法利用如何包含现在着色的图像,答案更简单在 StateListDrawable
。 (仅供参考,我尝试从我正在使用的 Xamarin C# 进行翻译,但下面的代码可能无法正确编译为 Java)
static Drawable recolorDrawable(Drawable icon, int toColor)
{
Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas myCanvas = new Canvas(bitmap);
icon.setColorFilter(toColor, PorterDuff.Mode.SRC_IN);
icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
icon.draw(myCanvas);
return new BitmapDrawable(context.getResources(), bitmap);
}
最后,公平地说,我对 Android 开发很陌生,感谢他在简化之前展示了我需要的部分。