首页 文章

修改android drawable的颜色

提问于
浏览
58

我希望能够使用相同的drawable来代表两者:

Blue icon

Red icon

作为相同的drawable,并根据一些编程值重新着色drawable,以便最终用户可以重新设置界面主题 .

做这个的最好方式是什么?我已经尝试过(并重复使用了图标)this previous S.O. question但是我无法将变化表示为色调的简单变化,因为它的饱和度和值也不同 .

是否最好将图标存储为我想要更改的区域中的所有白色?还是透明的?还是其他一些纯色?

是否有一些方法可以让你根据red_icon的颜色和blue_icon的颜色之间的差异找出矩阵?

6 回答

  • 1

    所以经过大量的试验和错误,阅读不同的文章,最重要的是,通过API演示(ColorFilters.java - 在com.example.android.apis.graphics中找到)我找到了解决方案 .

    对于实体图像,我发现最好使用滤镜PorterDuff.Mode.SRC_ATOP,因为它会将颜色叠加在源图像的顶部,允许您将颜色更改为您要查找的颜色 .

    对于更复杂的图像,如上图所示,我发现最好的办法是将整个图像着色为白色(FFFFFF),以便在进行PorterDuff.Mode.MULTIPLY时,最终得到正确的颜色,图像中的所有黑色(000000)都将保持黑色 .

    colorfilters.java向您展示如果您在画布上绘制它是如何完成的,但如果您只需要绘制一个drawable颜色,那么这将起作用:

    COLOR2 = Color.parseColor("#FF"+getColor());
    Mode mMode = Mode.SRC_ATOP;
    Drawable d = mCtx.getResources().getDrawable(R.drawable.image);
    d.setColorFilter(COLOR2,mMode)
    

    我创建了一个演示活动,使用一些API演示代码在每个颜色过滤器模式之间进行交换,以便针对不同的情况进行尝试,并发现它非常宝贵,所以我想我会在这里发布它 .

    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 .

  • 12

    如果您想在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上测试过

  • 3

    你的答案非常好 . 虽然,如果你使用Textview和embed drawable,这个解决方案也是实践:

    int colorARGB = R.color.your_color;
    Drawable[] textviewDrawables = drawerItem.getCompoundDrawables();
    // Left Drawable
    textviewDrawables[0].setColorFilter(colorARGB, PorterDuff.Mode.SRC_ATOP);
    
  • 18

    这是我在查看文档后所做的

    public PorterDuffColorFilter getDrawableFilter(){
            return new PorterDuffColorFilter(ContextCompat.getColor(this, R.color.color_black), PorterDuff.Mode.SRC_ATOP);
        }
    

    并称之为

    yourdrawable.setColorFilter(getDrawableFilter());
    
  • 2

    这在棒棒糖上真的很容易 . 制作一个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"/>
    
  • 104

    恕我直言,这比接受的答案更好 . 它源自此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:
     * 
    * {@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(); } } }

相关问题