如何改变一个可绘制的颜色在Android?

我在一个android应用程序上工作,我有一个可绘制的,我正在从源图像加载。在这个图像上,我想将所有的白色像素转换为不同的颜色,比如蓝色,然后缓存生成的Drawable对象,以便以后使用它。

例如,我有一个20x20的PNG文件,中间有一个白色的圆圈,圆圈之外的一切都是透明的。把白色圆圈变成蓝色并缓存结果的最好方法是什么?如果我想使用源图像来创建几个新的Drawables(比如蓝色、红色、绿色、橙色等),答案会改变吗?

我猜我想在某种程度上使用一个ColorMatrix,但我不确定如何。

381001 次浏览

检查这个示例代码"ColorMatrixSample.java"

/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


package com.example.android.apis.graphics;


import com.example.android.apis.R;


import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;


public class ColorMatrixSample extends GraphicsActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}


private static class SampleView extends View {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private ColorMatrix mCM = new ColorMatrix();
private Bitmap mBitmap;
private float mSaturation;
private float mAngle;


public SampleView(Context context) {
super(context);


mBitmap = BitmapFactory.decodeResource(context.getResources(),
R.drawable.balloons);
}


private static void setTranslate(ColorMatrix cm, float dr, float dg,
float db, float da) {
cm.set(new float[] {
2, 0, 0, 0, dr,
0, 2, 0, 0, dg,
0, 0, 2, 0, db,
0, 0, 0, 1, da });
}


private static void setContrast(ColorMatrix cm, float contrast) {
float scale = contrast + 1.f;
float translate = (-.5f * scale + .5f) * 255.f;
cm.set(new float[] {
scale, 0, 0, 0, translate,
0, scale, 0, 0, translate,
0, 0, scale, 0, translate,
0, 0, 0, 1, 0 });
}


private static void setContrastTranslateOnly(ColorMatrix cm, float contrast) {
float scale = contrast + 1.f;
float translate = (-.5f * scale + .5f) * 255.f;
cm.set(new float[] {
1, 0, 0, 0, translate,
0, 1, 0, 0, translate,
0, 0, 1, 0, translate,
0, 0, 0, 1, 0 });
}


private static void setContrastScaleOnly(ColorMatrix cm, float contrast) {
float scale = contrast + 1.f;
float translate = (-.5f * scale + .5f) * 255.f;
cm.set(new float[] {
scale, 0, 0, 0, 0,
0, scale, 0, 0, 0,
0, 0, scale, 0, 0,
0, 0, 0, 1, 0 });
}


@Override protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
float x = 20;
float y = 20;


canvas.drawColor(Color.WHITE);


paint.setColorFilter(null);
canvas.drawBitmap(mBitmap, x, y, paint);


ColorMatrix cm = new ColorMatrix();


mAngle += 2;
if (mAngle > 180) {
mAngle = 0;
}


//convert our animated angle [-180...180] to a contrast value of [-1..1]
float contrast = mAngle / 180.f;


setContrast(cm, contrast);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(mBitmap, x + mBitmap.getWidth() + 10, y, paint);


setContrastScaleOnly(cm, contrast);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(mBitmap, x, y + mBitmap.getHeight() + 10, paint);


setContrastTranslateOnly(cm, contrast);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(mBitmap, x, y + 2*(mBitmap.getHeight() + 10),
paint);


invalidate();
}
}
}

相关API可用在这里:

我可以用下面的代码做到这一点,这是从一个活动(布局是一个非常简单的,只包含一个ImageView,并没有张贴在这里)。

private static final int[] FROM_COLOR = new int[]{49, 179, 110};
private static final int THRESHOLD = 3;


public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.test_colors);


ImageView iv = (ImageView) findViewById(R.id.img);
Drawable d = getResources().getDrawable(RES);
iv.setImageDrawable(adjust(d));
}


private Drawable adjust(Drawable d)
{
int to = Color.RED;


//Need to copy to ensure that the bitmap is mutable.
Bitmap src = ((BitmapDrawable) d).getBitmap();
Bitmap bitmap = src.copy(Bitmap.Config.ARGB_8888, true);
for(int x = 0;x < bitmap.getWidth();x++)
for(int y = 0;y < bitmap.getHeight();y++)
if(match(bitmap.getPixel(x, y)))
bitmap.setPixel(x, y, to);


return new BitmapDrawable(bitmap);
}


private boolean match(int pixel)
{
//There may be a better way to match, but I wanted to do a comparison ignoring
//transparency, so I couldn't just do a direct integer compare.
return Math.abs(Color.red(pixel) - FROM_COLOR[0]) < THRESHOLD &&
Math.abs(Color.green(pixel) - FROM_COLOR[1]) < THRESHOLD &&
Math.abs(Color.blue(pixel) - FROM_COLOR[2]) < THRESHOLD;
}

我认为你实际上可以使用Drawable.setColorFilter( 0xffff0000, Mode.MULTIPLY )。这将把白色像素设置为红色,但我不认为它会影响透明像素。

看到可拉的# setColorFilter

如果你有一个纯色的可绘制对象,并且你想将其更改为不同的纯色,你可以使用ColorMatrixColorFilter。透明度得以保留。

int iColor = Color.parseColor(color);


int red   = (iColor & 0xFF0000) / 0xFFFF;
int green = (iColor & 0xFF00) / 0xFF;
int blue  = iColor & 0xFF;


float[] matrix = { 0, 0, 0, 0, red,
0, 0, 0, 0, green,
0, 0, 0, 0, blue,
0, 0, 0, 1, 0 };


ColorFilter colorFilter = new ColorMatrixColorFilter(matrix);
drawable.setColorFilter(colorFilter);

试试这段代码:

ImageView lineColorCode = (ImageView)convertView.findViewById(R.id.line_color_code);
int color = Color.parseColor("#AE6118"); //The color u want
lineColorCode.setColorFilter(color);

你应该为所有api这样做:

Drawable myIcon = getResources().getDrawable( R.drawable.button );
ColorFilter filter = new LightingColorFilter( Color.BLACK, Color.BLACK);
myIcon.setColorFilter(filter);

在你的活动中,你可以用一种颜色来着色你的PNG图像资源:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myColorTint();
setContentView(R.layout.activity_main);
}


private void myColorTint() {
int tint = Color.parseColor("#0000FF"); // R.color.blue;
PorterDuff.Mode mode = PorterDuff.Mode.SRC_ATOP;
// add your drawable resources you wish to tint to the drawables array...
int drawables[] = { R.drawable.ic_action_edit, R.drawable.ic_action_refresh };
for (int id : drawables) {
Drawable icon = getResources().getDrawable(id);
icon.setColorFilter(tint,mode);
}
}

当你使用r。drawable时。它应该用所需要的颜色着色。如果你需要额外的颜色,那么你应该能够.mutate()绘制。

我知道这个问题是在棒棒糖之前问的,但我想在Android 5上添加一个很好的方法来做到这一点。你创建了一个引用原始图形的xml绘图,并像这样设置着色:

<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_back"
android:tint="@color/red_tint"/>

根据isWorking字段更改可绘制颜色的简短示例。

我的形状xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="@android:color/holo_blue_bright" />
<corners android:radius="30dp" />
<size
android:height="15dp"
android:width="15dp" />
</shape>

我的改变方法:

private Drawable getColoredDrawable(int drawableResId, boolean isworking) {
Drawable d = getResources().getDrawable(R.drawable.shape);
ColorFilter filter = new LightingColorFilter(
isworking ? Color.GREEN : Color.RED,
isworking ? Color.GREEN : Color.RED);
d.setColorFilter(filter);
return d;
}

用法示例:

text1.setCompoundDrawablesWithIntrinsicBounds(getColoredDrawable(R.drawable.shape, isworking()), null, null, null);

这适用于所有有背景的东西:

Textview,按钮……

TextView text = (TextView) View.findViewById(R.id.MyText);
text.setBackgroundResource(Icon);
text.getBackground().setColorFilter(getResources().getColor(Color), PorterDuff.Mode.SRC_ATOP);

新的支持v4将tint带回api 4。

你可以这样做

public static Drawable setTint(Drawable d, int color) {
Drawable wrappedDrawable = DrawableCompat.wrap(d);
DrawableCompat.setTint(wrappedDrawable, color);
return wrappedDrawable;
}

我还使用ImageView图标(在ListView或设置屏幕)。但我认为有更简单的方法。

使用tint来改变所选图标的颜色覆盖。

在xml中,

android:tint="@color/accent"
android:src="@drawable/ic_event"

工作得很好,因为它来自AppCompat

view.getDrawable().mutate().setColorFilter(0xff777777, PorterDuff.Mode.MULTIPLY);

谢谢@sabadow

有很多解决方案,但没有人建议如果颜色资源XML文件已经有颜色,那么我们可以直接从那里选择如下:

ImageView imageView = (ImageView) findViewById(R.id.imageview);
imageView.setColorFilter(getString(R.color.your_color));

这段代码片段对我来说很有用:

PorterDuffColorFilter porterDuffColorFilter = new PorterDuffColorFilter(getResources().getColor(R.color.your_color),PorterDuff.Mode.MULTIPLY);


imgView.getDrawable().setColorFilter(porterDuffColorFilter);
imgView.setBackgroundColor(Color.TRANSPARENT)
当你使用一个库来为你做这件事时,这是非常非常简单的。 试试图书馆

你可以这样调用:

Icon.on(holderView).color(R.color.your_color).icon(R.mipmap.your_icon).put();

你可以使用Android支持compat库来解决这个问题。:)

 // mutate to not share its state with any other drawable
Drawable drawableWrap = DrawableCompat.wrap(drawable).mutate();
DrawableCompat.setTint(drawableWrap, ContextCompat.getColor(getContext(), R.color.your_color))

如果你在ImageView中有可绘制的集合,你可以用一行代码完成:

yourImageView.setColorFilter(context.getResources().getColor(R.color.YOUR_COLOR_HERE);
Int color = Color.GRAY;
// or int color = Color.argb(123,255,0,5);
// or int color = 0xaaff000;

在XML /res/values/color.xml中

<?xml version="1.0" encoding="utf-8">
<resources>
<color name="colorRed">#ff0000</color>
</resoures>

Java代码

int color = ContextCompat.getColor(context, R.color.colorRed);


GradientDrawable drawableBg = yourView.getBackground().mutate();
drawableBg.setColor(color);

太晚了,但以防有人需要:

   fun setDrawableColor(drawable: Drawable, color: Int) :Drawable {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
drawable.colorFilter = BlendModeColorFilter(color, BlendMode.SRC_ATOP)
return drawable
} else {
drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
return drawable
}
}

它适用于一些简单的绘图。我用它在一个简单的纯色矩形圆角形状和需要改变的颜色与不同的布局。

试试这个

android:backgroundTint="#101010"

试着android: backgroundTint =“@color / quantum_black_100"

Koltin解决方案使用视图绑定:

binding.avatar.drawable.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(R.color.white, BlendModeCompat.SRC_ATOP)

这使用了最新版本的核心androidx库。

我只是遇到了这个问题,并通过替换来解决它:

android:tint="@color/yellow_800"

到以下

app:tint="@color/yellow_800"