How to change colors of a Drawable in Android?

AndroidAndroid Drawable

Android Problem Overview


I'm working on an android application, and I have a drawable that I'm loading up from a source image. On this image, I'd like to convert all of the white pixels to a different color, say blue, and then cache the resultant Drawable object so I can use it later.

So for example say I have a 20x20 PNG file that has a white circle in the middle, and that everything outside the circle is transparent. What's the best way to turn that white circle blue and cache the results? Does the answer change if I want to use that source image to create several new Drawables (say blue, red, green, orange, etc)?

I'm guessing that I'll want to use a ColorMatrix in some way, but I'm not sure how.

Android Solutions


Solution 1 - Android

I think you can actually just use Drawable.setColorFilter( 0xffff0000, Mode.MULTIPLY ). This would set white pixels to red but I don't think it would affect the transparent pixels.

See Drawable#setColorFilter

Solution 2 - Android

Give this code a try:

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

Solution 3 - Android

I know this question was ask way before Lollipop but I would like to add a nice way to do this on Android 5.+. You make an xml drawable that references the original one and set tint on it like such:

<?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"/>

Solution 4 - Android

The new support v4 bring tint back to api 4.

you can do it like this

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

Solution 5 - Android

If you have a drawable that's a solid color and you want to change it to a differnet solid color, you can use a ColorMatrixColorFilter. Transparency is preserved.

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);

Solution 6 - Android

I also use ImageView for icons (in ListView or settings screen). But I think there is much simpler way to do that.

Use tint to change the color overlay on your selected icon.

In xml,

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

works fine since it comes from AppCompat

Solution 7 - Android

You should do this for all APIs:

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

Solution 8 - Android

I was able to do this with the following code, which is taken from an activity (the layout is a very simple one, just containing an ImageView, and is not posted here).

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;
}

Solution 9 - Android

You can solve it using Android support compat libraries. :)

 // 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))

Solution 10 - Android

In your Activity you can tint your PNG image resources with a single colour:

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);
    }
}

Now when you use the R.drawable.* it should be coloured with the desired tint. If you need additional colours then you should be able to .mutate() the drawable.

Solution 11 - Android

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

Thanks to @sabadow

Solution 12 - Android

This code snippet worked for me:

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

imgView.getDrawable().setColorFilter(porterDuffColorFilter);
imgView.setBackgroundColor(Color.TRANSPARENT)

Solution 13 - Android

If you have your drawable set to the ImageView you can do it with a 1 liner:

yourImageView.setColorFilter(context.getResources().getColor(R.color.YOUR_COLOR_HERE);

Solution 14 - Android

Too late but in case someone need it:

   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
        }
    }

Solution 15 - Android

This works with everything with background:

Textview, Button...

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

Solution 16 - Android

There are so many solution but nobody suggested if the color resource xml file already have color then we can pick directly from there also as below:

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

Solution 17 - Android

Check out this sample code "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();
        }
    }
}

The relevant API is available here:

Solution 18 - Android

Short example to change drawable color according to isWorking field.

My shape 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>

My method to change:

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;
}

Example of usage:

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

Solution 19 - Android

Int color = Color.GRAY; 
// or int color = Color.argb(123,255,0,5);
// or int color = 0xaaff000;

in XML /res/values/color.xml

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

Java Code

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

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

Solution 20 - Android

It works for some simple drawables. I used it on a simple solid color rect shape with rounded corners and needed to change that color with different layouts.

Try this

android:backgroundTint="#101010"

Solution 21 - Android

Try android:backgroundTint="@color/quantum_black_100"

Solution 22 - Android

Koltin solution using view binding:

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

This uses the latest version of the core androidx library.

Solution 23 - Android

I just encountered the issue and solved it by replacing:

android:tint="@color/yellow_800"

to the following

app:tint="@color/yellow_800"

Solution 24 - Android

It's very very simple when you use a library to do that for you. Try this library

You can call like this:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatt McMinnView Question on Stackoverflow
Solution 1 - Androidthom_nicView Answer on Stackoverflow
Solution 2 - AndroidNarenView Answer on Stackoverflow
Solution 3 - AndroidMinceManView Answer on Stackoverflow
Solution 4 - AndroidPeiView Answer on Stackoverflow
Solution 5 - AndroidMike HillView Answer on Stackoverflow
Solution 6 - Androidsud007View Answer on Stackoverflow
Solution 7 - Androidhoangtu23View Answer on Stackoverflow
Solution 8 - AndroidMatt McMinnView Answer on Stackoverflow
Solution 9 - AndroidRicardView Answer on Stackoverflow
Solution 10 - AndroidDavid DouglasView Answer on Stackoverflow
Solution 11 - AndroidHamidreza SadeghView Answer on Stackoverflow
Solution 12 - AndroidMehatabView Answer on Stackoverflow
Solution 13 - AndroidMartin NowosadView Answer on Stackoverflow
Solution 14 - AndroidMouaad Abdelghafour AITALIView Answer on Stackoverflow
Solution 15 - AndroidtoniView Answer on Stackoverflow
Solution 16 - AndroidPankajView Answer on Stackoverflow
Solution 17 - AndroidAdrianView Answer on Stackoverflow
Solution 18 - AndroiddeadfishView Answer on Stackoverflow
Solution 19 - AndroidVen RenView Answer on Stackoverflow
Solution 20 - AndroidJay ParikhView Answer on Stackoverflow
Solution 21 - AndroidSaurabhView Answer on Stackoverflow
Solution 22 - AndroidTop4oView Answer on Stackoverflow
Solution 23 - AndroidYaacov BiblowView Answer on Stackoverflow
Solution 24 - AndroidVansuita Jr.View Answer on Stackoverflow