我希望能够使用相同的drawable来代表两者:
和
作为相同的drawable,并根据一些编程值重新着色drawable,以便最终用户可以重新设置界面主题。
最好的方法是什么?我已尝试过(并重用了this previous S.O. question中的图标,但我无法将变化表示为色调的简单变化,因为它的饱和度和值也会有所不同。
最好将图标存储为我想要更改的区域中的所有白色吗?还是透明的?或其他一些纯色?
是否有一些方法可以根据red_icon的颜色和blue_icon的颜色之间的差异找出矩阵?
答案 0 :(得分:107)
经过大量的试验和错误,阅读不同的文章,最重要的是,通过API演示(ColorFilters.java - 在com.example.android.apis.graphics中找到)我找到了解决方案。
对于实体图像,我发现最好使用滤镜PorterDuff.Mode.SRC_ATOP,因为它会将颜色叠加在源图像的顶部,允许您将颜色更改为您要查找的颜色
对于更复杂的图像,如上图所示,我发现最好的办法是将整个图像着色为白色(FFFFFF),这样当你做PorterDuff.Mode.MULTIPLY时,你最终会得到正确的颜色和图像中的所有黑色(000000)将保持黑色。
colorfilters.java向您展示如果您在画布上绘制它是如何完成的,但如果您只需要绘制一个可绘制的颜色,那么这将起作用:
COLOR2 = Color.parseColor("#FF"+getColor());
Mode mMode = Mode.SRC_ATOP;
Drawable d = mCtx.getResources().getDrawable(R.drawable.image);
d.setColorFilter(COLOR2,mMode)
我创建了一个演示活动,使用一些API Demo代码在每种颜色过滤器模式之间进行交换,以便针对不同情况进行尝试,并发现它非常有价值,所以我想我会在这里发布。
public class ColorFilters extends GraphicsActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
private static class SampleView extends View {
private Activity mActivity;
private Drawable mDrawable;
private Drawable[] mDrawables;
private Paint mPaint;
private Paint mPaint2;
private float mPaintTextOffset;
private int[] mColors;
private PorterDuff.Mode[] mModes;
private int mModeIndex;
private Typeface futura_bold;
private AssetManager assets;
private static void addToTheRight(Drawable curr, Drawable prev) {
Rect r = prev.getBounds();
int x = r.right + 12;
int center = (r.top + r.bottom) >> 1;
int h = curr.getIntrinsicHeight();
int y = center - (h >> 1);
curr.setBounds(x, y, x + curr.getIntrinsicWidth(), y + h);
}
public SampleView(Activity activity) {
super(activity);
mActivity = activity;
Context context = activity;
setFocusable(true);
/**1. GET DRAWABLE, SET BOUNDS */
assets = context.getAssets();
mDrawable = context.getResources().getDrawable(R.drawable.roundrect_gray_button_bg_nine);
mDrawable.setBounds(0, 0, mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
mDrawable.setDither(true);
int[] resIDs = new int[] {
R.drawable.roundrect_gray_button_bg,
R.drawable.order_button_white,
R.drawable.yellowbar
};
mDrawables = new Drawable[resIDs.length];
Drawable prev = mDrawable;
for (int i = 0; i < resIDs.length; i++) {
mDrawables[i] = context.getResources().getDrawable(resIDs[i]);
mDrawables[i].setDither(true);
addToTheRight(mDrawables[i], prev);
prev = mDrawables[i];
}
/**2. SET Paint for writing text on buttons */
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(16);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint2 = new Paint(mPaint);
/** Calculating size based on font */
futura_bold = Typeface.createFromAsset(assets,
"fonts/futurastd-bold.otf");
//Determine size and offset to write text in label based on font size.
mPaint.setTypeface(futura_bold);
Paint.FontMetrics fm = mPaint.getFontMetrics();
mPaintTextOffset = (fm.descent + fm.ascent) * 0.5f;
mColors = new int[] {
0,
0xFFA60017,//WE USE THESE
0xFFC6D405,
0xFF4B5B98,
0xFF656565,
0xFF8888FF,
0xFF4444FF,
};
mModes = new PorterDuff.Mode[] {
PorterDuff.Mode.DARKEN,
PorterDuff.Mode.DST,
PorterDuff.Mode.DST_ATOP,
PorterDuff.Mode.DST_IN,
PorterDuff.Mode.DST_OUT,
PorterDuff.Mode.DST_OVER,
PorterDuff.Mode.LIGHTEN,
PorterDuff.Mode.MULTIPLY,
PorterDuff.Mode.SCREEN,
PorterDuff.Mode.SRC,
PorterDuff.Mode.SRC_ATOP,
PorterDuff.Mode.SRC_IN,
PorterDuff.Mode.SRC_OUT,
PorterDuff.Mode.SRC_OVER,
PorterDuff.Mode.XOR
};
mModeIndex = 0;
updateTitle();
}
private void swapPaintColors() {
if (mPaint.getColor() == 0xFF000000) {
mPaint.setColor(0xFFFFFFFF);
mPaint2.setColor(0xFF000000);
} else {
mPaint.setColor(0xFF000000);
mPaint2.setColor(0xFFFFFFFF);
}
mPaint2.setAlpha(0);
}
private void updateTitle() {
mActivity.setTitle(mModes[mModeIndex].toString());
}
private void drawSample(Canvas canvas, ColorFilter filter) {
/** Create a rect around bounds, ensure size offset */
Rect r = mDrawable.getBounds();
float x = (r.left + r.right) * 0.5f;
float y = (r.top + r.bottom) * 0.5f - mPaintTextOffset;
/**Set color filter to selected color
* create canvas (filled with this color)
* Write text using paint (new color)
*/
mDrawable.setColorFilter(filter);
mDrawable.draw(canvas);
/** If the text doesn't fit in the button, make the text size smaller until it does*/
final float size = mPaint.measureText("Label");
if((int) size > (r.right-r.left)) {
float ts = mPaint.getTextSize();
Log.w("DEBUG","Text size was"+ts);
mPaint.setTextSize(ts-2);
}
canvas.drawText("Sausage Burrito", x, y, mPaint);
/** Write the text and draw it onto the drawable*/
for (Drawable dr : mDrawables) {
dr.setColorFilter(filter);
dr.draw(canvas);
}
}
@Override protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFCCCCCC);
canvas.translate(8, 12);
for (int color : mColors) {
ColorFilter filter;
if (color == 0) {
filter = null;
} else {
filter = new PorterDuffColorFilter(color,
mModes[mModeIndex]);
}
drawSample(canvas, filter);
canvas.translate(0, 55);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
// update mode every other time we change paint colors
if (mPaint.getColor() == 0xFFFFFFFF) {
mModeIndex = (mModeIndex + 1) % mModes.length;
updateTitle();
}
swapPaintColors();
invalidate();
break;
}
return true;
}
}
}
如果您想测试它,可以直接从API Demos活动中复制另外两个依赖项GraphicsActivity.java和PictureLayout.java。
答案 1 :(得分:18)
在棒棒糖上这很容易做到。制作一个xml drawable并引用你的png并设置这样的色调:
<?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"/>
答案 2 :(得分:12)
你的回答非常好。虽然,如果您使用的是Textview和嵌入式drawable,这个解决方案也是可行的:
int colorARGB = R.color.your_color;
Drawable[] textviewDrawables = drawerItem.getCompoundDrawables();
// Left Drawable
textviewDrawables[0].setColorFilter(colorARGB, PorterDuff.Mode.SRC_ATOP);
答案 3 :(得分:3)
如果您想在ImageView中对图像应用滤色镜,您可以更轻松地实现它。只需在xml中的ImageView中使用属性android:tint
。
示例:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/your_drawable"
android:tint="@color/your_color" />
在Android 4.1.2和6.0.1上测试
答案 4 :(得分:2)
恕我直言,这比接受的答案更好。它源自此StackOverflow线程:Understanding the Use of ColorMatrix and ColorMatrixColorFilter to Modify a Drawable's Hue
使用示例:
ImageView imageView = ...;
Drawable drawable = imageView.getDrawable();
ColorFilter colorFilter = ColorFilterGenerator.from(drawable).to(Color.RED);
imageView.setColorFilter(colorFilter);
将课程复制到您的项目中:
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PictureDrawable;
import android.widget.ImageView;
/**
* Creates a {@link ColorMatrixColorFilter} to adjust the hue, saturation, brightness, or
* contrast of an {@link Bitmap}, {@link Drawable}, or {@link ImageView}.
* <p/>
* Example usage:
* <br/>
* {@code imageView.setColorFilter(ColorFilterGenerator.from(Color.BLUE).to(Color.RED));}
*
* @author Jared Rummler <jared.rummler@gmail.com>
*/
public class ColorFilterGenerator {
// Based off answer from StackOverflow
// See: https://stackoverflow.com/a/15119089/1048340
private ColorFilterGenerator() {
throw new AssertionError();
}
public static From from(Drawable drawable) {
return new From(drawableToBitmap(drawable));
}
public static From from(Bitmap bitmap) {
return new From(bitmap);
}
public static From from(int color) {
return new From(color);
}
// --------------------------------------------------------------------------------------------
private static final double DELTA_INDEX[] = {
0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, 0.12, 0.14, 0.15, 0.16, 0.17, 0.18,
0.20, 0.21, 0.22, 0.24, 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, 0.44,
0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89,
0.92, 0.95, 0.98, 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, 1.60, 1.66, 1.72,
1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6,
3.8, 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4,
9.6, 9.8, 10.0
};
public static void adjustHue(ColorMatrix cm, float value) {
value = cleanValue(value, 180f) / 180f * (float) Math.PI;
if (value == 0) {
return;
}
float cosVal = (float) Math.cos(value);
float sinVal = (float) Math.sin(value);
float lumR = 0.213f;
float lumG = 0.715f;
float lumB = 0.072f;
float[] mat = new float[]{
lumR + cosVal * (1 - lumR) + sinVal * (-lumR),
lumG + cosVal * (-lumG) + sinVal * (-lumG),
lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0,
lumR + cosVal * (-lumR) + sinVal * (0.143f),
lumG + cosVal * (1 - lumG) + sinVal * (0.140f),
lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)),
lumG + cosVal * (-lumG) + sinVal * (lumG),
lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f,
0f, 1f
};
cm.postConcat(new ColorMatrix(mat));
}
public static void adjustBrightness(ColorMatrix cm, float value) {
value = cleanValue(value, 100);
if (value == 0) {
return;
}
float[] mat = new float[]{
1, 0, 0, 0, value, 0, 1, 0, 0, value, 0, 0, 1, 0, value, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1
};
cm.postConcat(new ColorMatrix(mat));
}
public static void adjustContrast(ColorMatrix cm, int value) {
value = (int) cleanValue(value, 100);
if (value == 0) {
return;
}
float x;
if (value < 0) {
x = 127 + value / 100 * 127;
} else {
x = value % 1;
if (x == 0) {
x = (float) DELTA_INDEX[value];
} else {
x = (float) DELTA_INDEX[(value << 0)] * (1 - x)
+ (float) DELTA_INDEX[(value << 0) + 1] * x;
}
x = x * 127 + 127;
}
float[] mat = new float[]{
x / 127, 0, 0, 0, 0.5f * (127 - x), 0, x / 127, 0, 0, 0.5f * (127 - x), 0, 0,
x / 127, 0, 0.5f * (127 - x), 0, 0, 0, 1, 0, 0, 0, 0, 0, 1
};
cm.postConcat(new ColorMatrix(mat));
}
public static void adjustSaturation(ColorMatrix cm, float value) {
value = cleanValue(value, 100);
if (value == 0) {
return;
}
float x = 1 + ((value > 0) ? 3 * value / 100 : value / 100);
float lumR = 0.3086f;
float lumG = 0.6094f;
float lumB = 0.0820f;
float[] mat = new float[]{
lumR * (1 - x) + x, lumG * (1 - x), lumB * (1 - x), 0, 0, lumR * (1 - x),
lumG * (1 - x) + x, lumB * (1 - x), 0, 0, lumR * (1 - x), lumG * (1 - x),
lumB * (1 - x) + x, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1
};
cm.postConcat(new ColorMatrix(mat));
}
// --------------------------------------------------------------------------------------------
private static float cleanValue(float p_val, float p_limit) {
return Math.min(p_limit, Math.max(-p_limit, p_val));
}
private static float[] getHsv(int color) {
float[] hsv = new float[3];
Color.RGBToHSV(Color.red(color), Color.green(color), Color.blue(color), hsv);
return hsv;
}
/**
* Converts a {@link Drawable} to a {@link Bitmap}
*
* @param drawable
* The {@link Drawable} to convert
* @return The converted {@link Bitmap}.
*/
private static Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof PictureDrawable) {
PictureDrawable pictureDrawable = (PictureDrawable) drawable;
Bitmap bitmap = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(),
pictureDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawPicture(pictureDrawable.getPicture());
return bitmap;
}
int width = drawable.getIntrinsicWidth();
width = width > 0 ? width : 1;
int height = drawable.getIntrinsicHeight();
height = height > 0 ? height : 1;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
/**
* Calculate the average red, green, blue color values of a bitmap
*
* @param bitmap
* a {@link Bitmap}
* @return
*/
private static int[] getAverageColorRGB(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int size = width * height;
int[] pixels = new int[size];
int r, g, b;
r = g = b = 0;
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
for (int i = 0; i < size; i++) {
int pixelColor = pixels[i];
if (pixelColor == Color.TRANSPARENT) {
size--;
continue;
}
r += Color.red(pixelColor);
g += Color.green(pixelColor);
b += Color.blue(pixelColor);
}
r /= size;
g /= size;
b /= size;
return new int[]{
r, g, b
};
}
/**
* Calculate the average color value of a bitmap
*
* @param bitmap
* a {@link Bitmap}
* @return
*/
private static int getAverageColor(Bitmap bitmap) {
int[] rgb = getAverageColorRGB(bitmap);
return Color.argb(255, rgb[0], rgb[1], rgb[2]);
}
// Builder
// --------------------------------------------------------------------------------------------
public static final class Builder {
int hue;
int contrast;
int brightness;
int saturation;
public Builder setHue(int hue) {
this.hue = hue;
return this;
}
public Builder setContrast(int contrast) {
this.contrast = contrast;
return this;
}
public Builder setBrightness(int brightness) {
this.brightness = brightness;
return this;
}
public Builder setSaturation(int saturation) {
this.saturation = saturation;
return this;
}
public ColorFilter build() {
ColorMatrix cm = new ColorMatrix();
adjustHue(cm, hue);
adjustContrast(cm, contrast);
adjustBrightness(cm, brightness);
adjustSaturation(cm, saturation);
return new ColorMatrixColorFilter(cm);
}
}
public static final class From {
final int oldColor;
private From(Bitmap bitmap) {
oldColor = getAverageColor(bitmap);
}
private From(int oldColor) {
this.oldColor = oldColor;
}
public ColorFilter to(int newColor) {
float[] hsv1 = getHsv(oldColor);
float[] hsv2 = getHsv(newColor);
int hue = (int) (hsv2[0] - hsv1[0]);
int saturation = (int) (hsv2[1] - hsv1[1]);
int brightness = (int) (hsv2[2] - hsv1[2]);
return new ColorFilterGenerator.Builder()
.setHue(hue)
.setSaturation(saturation)
.setBrightness(brightness)
.build();
}
}
}
答案 5 :(得分:2)
这是我在查看文档后所做的事情
public PorterDuffColorFilter getDrawableFilter(){
return new PorterDuffColorFilter(ContextCompat.getColor(this, R.color.color_black), PorterDuff.Mode.SRC_ATOP);
}
并称之为
yourdrawable.setColorFilter(getDrawableFilter());