204

I'm trying to change the color on a white marker image by code. I have read that the code below should change the color, but my marker remains white.

Drawable.setColorFilter( 0xffff0000, Mode.MULTIPLY )

Did I miss something? Is there any other way to change colors on my drawables located in my res folder?

Johan
  • 35,120
  • 54
  • 178
  • 293
  • accepted answer didn't work for me..used this [answer][1], [1]: http://stackoverflow.com/questions/5940825/android-change-shape-color-in-runtime – shyam.y Jan 16 '15 at 15:10
  • I think all the answers here change the background color, but not color of the image. Im i right? can anyone tell me please? I tried all the solutions here and also on same questions on stackoverflow, but they change only background color in may case. So i think, we can only change background color, but not the images color. I'm I right? – Shirish Herwade Apr 20 '15 at 12:44
  • Check this answer: https://stackoverflow.com/a/66479081/3503855 – Anis LOUNIS aka AnixPasBesoin Mar 05 '21 at 17:49

20 Answers20

346

Try this:

Drawable unwrappedDrawable = AppCompatResources.getDrawable(context, R.drawable.my_drawable); 
Drawable wrappedDrawable = DrawableCompat.wrap(unwrappedDrawable);
DrawableCompat.setTint(wrappedDrawable, Color.RED);    

Using DrawableCompat is important because it provides backwards compatibility and bug fixes on API 22 devices and earlier.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
ρяσѕρєя K
  • 132,198
  • 53
  • 198
  • 213
  • Hmm, the color remains white. Could it have to do with the hello mapview `OverlayItems` class that might be causing the problem? Its a regular drawable from my res folder, nothing special... – Johan Jul 07 '12 at 16:27
  • 31
    You might prefer PorterDuff.Mode.SRC_IN if you want it to work with a wider range of source colors. – Lorne Laliberte Jul 16 '15 at 19:27
  • PorterDuff.Mode.MULTIPLY did not changed anything for me ( Black star with transparent background). i used the PorterDuff.Mode.SRC_ATOP for coloring the actual bitmap. – Viktor Petrovski Mar 09 '16 at 11:54
  • There's also a convenience method you can use: `setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)` – CorayThan Feb 08 '17 at 00:25
  • 1
    PorterDuffColorFilter constructor takes ARGB color format – RichX Mar 23 '17 at 09:31
  • 3
    will be interesting to mutate the drawable with #mutate() to avoid share its state with any other drawable, otherwise if you reuse the drawable could have wrong color. – Ricard Mar 27 '20 at 18:02
  • The drawables are shared amongst all getDrawable from resources, hence the mutate() call is required to be able to change the tint of a drawable, without altering all the drawables associates with that resource ID, see https://stackoverflow.com/a/44593641/5555218 – Ricard Sep 18 '20 at 09:55
163

You can try this for svg vector drawable

DrawableCompat.setTint(
    DrawableCompat.wrap(myImageView.getDrawable()),
    ContextCompat.getColor(context, R.color.another_nice_color)
);
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
amorenew
  • 10,760
  • 10
  • 47
  • 69
  • 7
    Best way I've seen for svg. – apSTRK Jan 18 '17 at 21:44
  • 1
    prefer this over the accepted answer, although both will work, but with this one I don't have to worry about what drawable to set, i just get the one already there, and it's also backward compatible, great! – usernotnull Jun 29 '17 at 20:17
  • 1
    Best answer when nothing worked iot work like a charm! Thanks a lot! Note: It also works for when you have a xml drawable in your imageView/AppCompatImageView – Sjd Sep 15 '17 at 13:10
  • 1
    How to remove it programatically ? – Hardik Joshi Oct 04 '18 at 09:04
  • 3
    @HardikJoshi Documentation says: *To clear the tint, pass `null` to `Drawable#setTintList(ColorStateList)`* – arekolek Jan 11 '19 at 15:55
  • Unfortunately, this overrides the set stroke in the xml file, whereas the color filter option doesn't – Big_Chair May 12 '19 at 11:01
  • 1
    Correction, it only does so when not setting a mode. When using `DrawableCompat.setTintMode(bgDrawable, PorterDuff.Mode.MULTIPLY)` before applying the tint, it works the same as color filter. – Big_Chair May 12 '19 at 11:08
  • Remember to use `mutate()` or else you'd change the colour of the drawable globally! – ericn Jul 07 '21 at 15:07
37

You may need to call mutate() on the drawable or else all icons are affected.

Drawable icon = ContextCompat.getDrawable(getContext(), R.drawable.ic_my_icon).mutate();
TypedValue typedValue = new TypedValue();
getContext().getTheme().resolveAttribute(R.attr.colorIcon, typedValue, true);
icon.setColorFilter(typedValue.data, PorterDuff.Mode.SRC_ATOP);
shicky
  • 1,193
  • 14
  • 21
33

You can try this for ImageView. using setColorFilter().

imageView.setColorFilter(ContextCompat.getColor(context, R.color.colorWhite));
Jaydip Meghapara
  • 2,687
  • 1
  • 15
  • 14
22

Another way to do this on Lollipop, android 5.+ is setting a tint on a bitmap drawable 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"/>

This will work for you if you have a limited number of colors you want to use on your drawables. Check out my blog post for more information.

MinceMan
  • 7,483
  • 3
  • 38
  • 40
  • 2
    Nice! Btw, this seems to work fine on pre-Lollipop too. (Just tested this with `minSdkVersion 16` and Android 4.1.1 device.) – Jonik Mar 03 '15 at 12:16
  • When creating a bitmap this way, it does not stretch to fit the layout as it would when using `android:background="..."`. Pretty strange! – Prince May 19 '15 at 10:45
  • I think that's because you are not creating a nine patch here. – MinceMan May 19 '15 at 12:39
  • Sorry this page does not exist =( – Linh Jul 29 '16 at 07:41
  • @Jonik The answers in your provided question are irrelevant. This question is asking for the way to change *Drawable*'s colour, not ImageView. – Antony.H Feb 02 '17 at 04:45
13

I have wrote a generic function in which you can pass context, icon is id drawable/mipmap image icon and new color which you need for that icon.

This function returns a drawable.

public static Drawable changeDrawableColor(Context context,int icon, int newColor) {
    Drawable mDrawable = ContextCompat.getDrawable(context, icon).mutate(); 
    mDrawable.setColorFilter(new PorterDuffColorFilter(newColor, PorterDuff.Mode.SRC_IN)); 
    return mDrawable;
} 

changeDrawableColor(getContext(),R.mipmap.ic_action_tune, Color.WHITE);
Sachin Tanpure
  • 1,068
  • 11
  • 12
10

You could try a ColorMatrixColorFilter, since your key color is white:

// Assuming "color" is your target color
float r = Color.red(color) / 255f;
float g = Color.green(color) / 255f;
float b = Color.blue(color) / 255f;

ColorMatrix cm = new ColorMatrix(new float[] {
        // Change red channel
        r, 0, 0, 0, 0,
        // Change green channel
        0, g, 0, 0, 0,
        // Change blue channel
        0, 0, b, 0, 0,
        // Keep alpha channel
        0, 0, 0, 1, 0,
});
ColorMatrixColorFilter cf = new ColorMatrixColorFilter(cm);
myDrawable.setColorFilter(cf);
JJD
  • 50,076
  • 60
  • 203
  • 339
tiguchi
  • 5,392
  • 1
  • 33
  • 39
10

This worked for me. Make sure to put "ff" between 0x and color code. Like this 0xff2196F3

Drawable mDrawable = ContextCompat.getDrawable(MainActivity.this,R.drawable.ic_vector_home);
                    mDrawable.setColorFilter(new
                            PorterDuffColorFilter(0xff2196F3,PorterDuff.Mode.SRC_IN));
Bek
  • 7,790
  • 4
  • 18
  • 31
  • Hi @Bek welcome to stackoverflow. If this worked for you, it would be very helpful to include a jsfiddle with minimal solution to show that. It will help the person who posted question to understand properly. – Arjun Chaudhary Nov 15 '17 at 04:21
6

Same as the accepted answer but a simpler convenience method:

val myDrawable = ContextCompat.getDrawable(context, R.drawable.my_drawable)
myDrawable.setColorFilter(Color.GREEN, PorterDuff.Mode.SRC_IN)
setCompoundDrawablesWithIntrinsicBounds(myDrawable, null, null, null)

Note, the code here is Kotlin.

CorayThan
  • 17,174
  • 28
  • 113
  • 161
6

For those who use Kotlin a simple extension function:

fun Drawable.tint(context: Context,  @ColorRes color: Int) {
    DrawableCompat.setTint(this, context.resources.getColor(color, context.theme))
}

and then simply do

background.tint(context, R.color.colorPrimary)
Chapz
  • 605
  • 7
  • 13
5

Use this: For java

view.getBackground().setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_OVER)

for Kotlin

view.background.setColorFilter(Color.parseColor("#343434"),PorterDuff.Mode.SRC_OVER)

you can use PorterDuff.Mode.SRC_ATOP, if your background has rounded corners etc.

Ravi.Dudi
  • 1,284
  • 14
  • 14
3

You may want to try Mode.LIGHTEN or Mode.DARKEN. The Android Javadocs are horrible at explaining what the PorterDuff Modes do. You can take a look at them here: PorterDuff | Android

I suggest looking around at Compositing on Mozilla's site here. (They don't have all the modes that android does but they have a lot of them)

groovecoder
  • 1,551
  • 1
  • 17
  • 27
sebsebmc
  • 112
  • 4
2

Syntax

"your image name".setColorFilter("your context".getResources().getColor("color name"));

Example

myImage.setColorFilter(mContext.getResources().getColor(R.color.deep_blue_new));
ArteFact
  • 517
  • 4
  • 14
2

You can change your drawable color in this way:

background = view.findViewById(R.id.background)

val uDrawable = AppCompatResources.getDrawable(view.context, R.drawable.background)
uDrawable?.let {
      val wDrawable = DrawableCompat.wrap(it)
      DrawableCompat.setTint(wDrawable, ContextCompat.getColor(view.context, 
                                                      color /*specify your int color code*/))
      background.background = wDrawable
}
Ali Azaz Alam
  • 1,782
  • 1
  • 16
  • 27
2

SDK >= 21 one line myIconImageView.getDrawable().setTint(getResources().getColor(myColor))

close_file
  • 331
  • 2
  • 5
  • Pretty nice, I recommend to use `Drawable newDrawable = myDrawable.mutate().setTint(getResources().getColor(myColor))` to avoid changing it globally – FreddaP Mar 03 '22 at 14:01
1

Kotlin Version

val unwrappedDrawable =
            AppCompatResources.getDrawable(this, R.drawable.your_drawable)
        val wrappedDrawable = DrawableCompat.wrap(unwrappedDrawable!!)
DrawableCompat.setTint(wrappedDrawable, Color.RED)
0

This is what i did:

public static Drawable changeDrawableColor(int drawableRes, int colorRes, Context context) {
    //Convert drawable res to bitmap
    final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), drawableRes);
    final Bitmap resultBitmap = Bitmap.createBitmap(bitmap, 0, 0,
            bitmap.getWidth() - 1, bitmap.getHeight() - 1);
    final Paint p = new Paint();
    final Canvas canvas = new Canvas(resultBitmap);
    canvas.drawBitmap(resultBitmap, 0, 0, p);

    //Create new drawable based on bitmap
    final Drawable drawable = new BitmapDrawable(context.getResources(), resultBitmap);
    drawable.setColorFilter(new
            PorterDuffColorFilter(context.getResources().getColor(colorRes), PorterDuff.Mode.MULTIPLY));
    return drawable;
}
Edwin
  • 461
  • 1
  • 5
  • 14
0

Create Method like this :

//CHANGE ICON COLOR
private void changeIconColor(Context context ,int drawable){
    Drawable unwrappedDrawable = AppCompatResources.getDrawable(context, drawable);
    assert unwrappedDrawable != null;
    Drawable wrappedDrawable = DrawableCompat.wrap(unwrappedDrawable);
    DrawableCompat.setTint(wrappedDrawable, getResources().getColor(R.color.colorAccent));
}

and use it like it :

    changeIconColor(this,R.drawable.ic_home);
Sana Ebadi
  • 6,656
  • 2
  • 44
  • 44
0

Easiest Way to do it :

imageView.setColorFilter(Color.rgb(r, g b));

or

imageView.setColorFilter(Color.argb(a, r, g, b));

a, r, g, b : Color argb values.

Anubhav
  • 1,984
  • 22
  • 17
0

Long story short :

May 2023 Kotlin (all APIs):

 DrawableCompat.wrap
     (AppCompatResources.getDrawable(ctx, R.drawable.myDrawable)!!)
    .mutate()
    .also { DrawableCompat.setTint(it,0xFFff0000.toInt()) }

⚠ don't forget the mutate, a mutable drawable is guaranteed to not share its state with any other! This is especially useful when you need to modify properties of drawables loaded from resources. By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification. Calling this method on a mutable Drawable will have no effect.

Old - Java :

public Drawable getColoredDrawable(@DrawableRes int resid,int color){
    Drawable drawable= ContextCompat.getDrawable(context, resid).mutate();
    DrawableCompat.setTint(drawable, color);
    return drawable;
}
ucMedia
  • 4,105
  • 4
  • 38
  • 46