修改android drawable的颜色

ste*_*ory 60 android themes drawable

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

蓝色图标红色图标

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

做这个的最好方式是什么?我曾尝试过(并重用了之前的图标)这个以前的问题,但我无法将这种变化表现为色调的简单变化,因为它的饱和度和值也各不相同.

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

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

ste*_*ory 107

所以经过大量的试验和错误,阅读不同的文章,最重要的是,通过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)
Run Code Online (Sandbox Code Playgroud)

我创建了一个演示活动,使用一些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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想测试它,可以直接从API Demos活动复制另外两个依赖项GraphicsActivity.java和PictureLayout.java.

  • 我不太清楚你如何做你提到的,"整个图像的颜色为白色(FFFFFF),这样当你做PorterDuff.Mode.MULTIPLY时,你最终会得到正确的颜色,而所有的黑色(000000)你的形象将保持黑色." 你能举个例子吗? (5认同)
  • @steve_gregory"整个图像的颜色为白色(FFFFFF)"是什么意思? (3认同)

Min*_*Man 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"/>
Run Code Online (Sandbox Code Playgroud)


Jes*_*tro 12

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

int colorARGB = R.color.your_color;
Drawable[] textviewDrawables = drawerItem.getCompoundDrawables();
// Left Drawable
textviewDrawables[0].setColorFilter(colorARGB, PorterDuff.Mode.SRC_ATOP);
Run Code Online (Sandbox Code Playgroud)