216

Android Studio now supports vector assets on 21+ and will generate pngs for lower versions at compile time. I have a vector asset (from the Material Icons) that I want to change the fill color. This works on 21+, but the generated pngs do not change color. Is there a way to do this?

<vector android:height="48dp" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/primary" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>

Patrick Jackson
  • 18,766
  • 22
  • 81
  • 141

18 Answers18

414

Don't edit the vector assets directly. If you're using a vector drawable in an ImageButton, just choose your color in android:tint.

<ImageButton
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:id="@+id/button"
        android:src="@drawable/ic_more_vert_24dp"
        android:tint="@color/primary" />
HughHughTeotl
  • 5,439
  • 3
  • 34
  • 49
YYYY-MM-DD
  • 4,411
  • 1
  • 15
  • 14
  • 25
    tinting only works on 21+ devices, do you have any suggestion for pre-lollipop devices – mudit Nov 26 '15 at 17:23
  • 12
    android:tint works on all android versions since APIv1. What you mean is drawableTint. – YYYY-MM-DD Mar 23 '16 at 21:34
  • 37
    `android:tint` must be after `android:src` – EmmanuelMess Apr 10 '16 at 12:38
  • 7
    What about `drawableLeft` in `Button`? – Pratik Butani May 14 '16 at 17:33
  • 9
    @mudit try using a vector with fillColor="#colorvalue", don't use a @ color reference because they only work SDK 21+ for vectors (so not for the generated PNG's) – PieterAelse May 25 '16 at 12:01
  • 4
    What if I'm using this asset in a menu Item? @PieterAelse – Michael Obi Oct 15 '16 at 06:37
  • @MichaelObi Not sure, just try on both pre-SDK21 and SDK21+ – PieterAelse Oct 17 '16 at 14:44
  • 1
    you must use app:srcCompat instead of android:src for supporting pre-lolipop devices – Leo DroidCoder Nov 02 '16 at 13:10
  • 3
    @MichaelObi This is the same question I had. There is no android:tint attribute for an `item` in a menu .xml file. – Philip Stratford Dec 16 '16 at 16:21
  • 2
    @EmmanuelMess Why does `tint` have to go after `src`? That makes no sense, attributes are loaded in the order that Java code is written... See https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/ImageView.java#205 (tint) and https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/ImageView.java#188 (src) Am I missing something? – milosmns Oct 23 '17 at 18:30
  • @milosmns ok, I commented that more than a year ago, it might have been a bug, I do not remember, but it should be as you say. The bug might have to do with the fact that vectors have colors loaded as properties of the elements inside. – EmmanuelMess Oct 23 '17 at 19:35
  • 2
    @YYYY-MM-DD Why not change the fillColor directly on the vector asset? I mean, I know that I can apply a tint programmatically or through xml attributes, but if I want my drawables to all be white, why not change the fill color instead of keeping them black and applying a tint? Is there any advantage in keeping the vector drawables with a black fill color? – ifeins Feb 09 '18 at 09:33
  • Try this to changes color programmatically "imageView.setColorFilter(ContextCompat.getColor(activity, R.color.colorSelected), android.graphics.PorterDuff.Mode.MULTIPLY);" And make sure to add this "vectorDrawables.useSupportLibrary = true" in build.gradle – E Player Plus Feb 24 '19 at 16:46
109

You can do it.

BUT you cannot use @color references for colors (..lame), otherwise it will work only for L+

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
<path
    android:fillColor="#FFAABB"
    android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zm-6,0C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>

urSus
  • 12,492
  • 12
  • 69
  • 89
  • 11
    This should be the accepted answer! @color references don't work in vectors pre-Lollipop (so vector -> PNG conversion) https://code.google.com/p/android/issues/detail?id=186431 – PieterAelse May 25 '16 at 11:59
  • 6
    @color references can now be used for the fillColor attribute for all Android versions, however it does not support color state lists. – TheIT Dec 13 '16 at 20:28
  • 1
    It looks like the way to do vector state lists is with [AnimatedStateListDrawable](https://developer.android.com/reference/android/graphics/drawable/AnimatedStateListDrawable.html)s – gMale Dec 14 '16 at 21:47
  • 1
    @TheIT what do I have to enable it? Doesnt seem to work for me – urSus Dec 23 '16 at 01:53
  • @PieterAelse I'm not sure, what if you want to use the same asset but with different backgrounds(tints like in previous answer). In your solution you will have several instances of same resource but with different fill color – Anton Makov Feb 27 '18 at 21:14
  • @AntonMakov yes, ofc its only for static things – urSus Mar 01 '18 at 04:15
  • @PieterAelse, I'm able to refer color references and it's working fine API 19. e.g. `android:fillColor="@color/icon_color"` – wangadu Oct 17 '18 at 19:17
  • 1
    does not work iven when setting color directly. Still white. – Waldmann Aug 26 '20 at 20:44
74

As said in other answers, don't edit the vector drawable directly, instead you can tint in java code, like that:

    mWrappedDrawable = mDrawable.mutate();
    mWrappedDrawable = DrawableCompat.wrap(mWrappedDrawable);
    DrawableCompat.setTint(mWrappedDrawable, mColor);
    DrawableCompat.setTintMode(mWrappedDrawable, PorterDuff.Mode.SRC_IN);

And for the sake of simplicity, I have created a helper class:

import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;

/**
 * {@link Drawable} helper class.
 *
 * @author Filipe Bezerra
 * @version 18/01/2016
 * @since 18/01/2016
 */
public class DrawableHelper {
    @NonNull Context mContext;
    @ColorRes private int mColor;
    private Drawable mDrawable;
    private Drawable mWrappedDrawable;

    public DrawableHelper(@NonNull Context context) {
        mContext = context;
    }

    public static DrawableHelper withContext(@NonNull Context context) {
        return new DrawableHelper(context);
    }

    public DrawableHelper withDrawable(@DrawableRes int drawableRes) {
        mDrawable = ContextCompat.getDrawable(mContext, drawableRes);
        return this;
    }

    public DrawableHelper withDrawable(@NonNull Drawable drawable) {
        mDrawable = drawable;
        return this;
    }

    public DrawableHelper withColor(@ColorRes int colorRes) {
        mColor = ContextCompat.getColor(mContext, colorRes);
        return this;
    }

    public DrawableHelper tint() {
        if (mDrawable == null) {
            throw new NullPointerException("É preciso informar o recurso drawable pelo método withDrawable()");
        }

        if (mColor == 0) {
            throw new IllegalStateException("É necessário informar a cor a ser definida pelo método withColor()");
        }

        mWrappedDrawable = mDrawable.mutate();
        mWrappedDrawable = DrawableCompat.wrap(mWrappedDrawable);
        DrawableCompat.setTint(mWrappedDrawable, mColor);
        DrawableCompat.setTintMode(mWrappedDrawable, PorterDuff.Mode.SRC_IN);

        return this;
    }

    @SuppressWarnings("deprecation")
    public void applyToBackground(@NonNull View view) {
        if (mWrappedDrawable == null) {
            throw new NullPointerException("É preciso chamar o método tint()");
        }

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            view.setBackground(mWrappedDrawable);
        } else {
            view.setBackgroundDrawable(mWrappedDrawable);
        }
    }

    public void applyTo(@NonNull ImageView imageView) {
        if (mWrappedDrawable == null) {
            throw new NullPointerException("É preciso chamar o método tint()");
        }

        imageView.setImageDrawable(mWrappedDrawable);
    }

    public void applyTo(@NonNull MenuItem menuItem) {
        if (mWrappedDrawable == null) {
            throw new NullPointerException("É preciso chamar o método tint()");
        }

        menuItem.setIcon(mWrappedDrawable);
    }

    public Drawable get() {
        if (mWrappedDrawable == null) {
            throw new NullPointerException("É preciso chamar o método tint()");
        }

        return mWrappedDrawable;
    }
}

To use just do the following:

    DrawableHelper
            .withContext(this)
            .withColor(R.color.white)
            .withDrawable(R.drawable.ic_search_24dp)
            .tint()
            .applyTo(mSearchItem);

Or:

    final Drawable drawable = DrawableHelper
            .withContext(this)
            .withColor(R.color.white)
            .withDrawable(R.drawable.ic_search_24dp)
            .tint()
            .get();

    actionBar.setHomeAsUpIndicator(drawable);
Filipe Bezerra de Sousa
  • 2,874
  • 1
  • 17
  • 17
46

To change vector image color you can directly use android:tint="@color/colorAccent"

<ImageView
        android:id="@+id/ivVectorImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_account_circle_black_24dp"
        android:tint="@color/colorAccent" />

To change color programatically

ImageView ivVectorImage = (ImageView) findViewById(R.id.ivVectorImage);
ivVectorImage.setColorFilter(getResources().getColor(R.color.colorPrimary));
Rana Ranvijay Singh
  • 6,055
  • 3
  • 38
  • 54
  • getColor() is deprecated – David Jul 21 '17 at 13:37
  • How to use it for TextView's drawable*** ? – Hemant Kaushik Mar 22 '18 at 05:57
  • getColor(ResId) is deprecated @David, but `getColor(ResId, Theme)` is not. Or you can use `ResourcesCompat.getColor(getResources(), R.color.primary, null);` if you don’t care about the theme… or if your context/policy delegate IS an activity, you can do `getTheme()` for that last parameter. – Martin Marconcini Aug 02 '18 at 21:20
16

Currently the working soloution is android:fillColor="#FFFFFF"

Nothing worked for me except hard coding in the vector

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24.0"
      android:fillColor="#FFFFFF"
    android:viewportHeight="24.0">
<path
    android:fillColor="#FFFFFF"
    android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zm-6,0C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>

However, fillcolor and tint might work soon. Please see this discussion for more information:

https://code.google.com/p/android/issues/detail?id=186431

Also the colors mighr stick in the cache so deleting app for all users might help.

sivi
  • 10,654
  • 2
  • 52
  • 51
12

Update: AppCompat support

Other answers suspecting if android:tint will work on only 21+ devices only, AppCompat(v23.2.0 and above) now provides a backward compatible handling of tint attribute.

So, the course of action would be to use AppCompatImageView and app:srcCompat(in AppCompat namespace) instead of android:src(Android namespace).

Here is an example(AndroidX: This is androidx.appcompat.widget.AppCompatImageView ;)):

<android.support.v7.widget.AppCompatImageView
        android:id="@+id/credits_material_icon"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="16dp"
        android:layout_marginStart="16dp"
        android:scaleType="fitCenter"
        android:tint="#ffd2ee"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:srcCompat="@drawable/ic_dollar_coin_stack" />

And don't forget to enable vector drawable support in gradle:

vectorDrawables.useSupportLibrary = true 
Manish Kumar Sharma
  • 12,982
  • 9
  • 58
  • 105
7

Android studio now supports vectors pre-lollipop. No PNG conversion. You can still change your fill color and it will work.

In you ImageView, use

 app:srcCompat="@drawable/ic_more_vert_24dp"

In your gradle file,

 // Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
   }  
 }  

 compile 'com.android.support:design:23.4.0'
Sayooj Valsan
  • 536
  • 5
  • 16
4
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="//Your Color Code//">
  <path
      android:fillColor="@android:color/white"
      android:pathData="M11,9.16V2c-5,0.5 -9,4.79 -9,10s4,9.5 9"/>
</vector>
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 01 '22 at 09:22
  • Thanks a lot! This is the easiest way to change the color. android:tint = "//Your Color Code//" – Shubham Nanche Mar 09 '22 at 12:09
3

If the vectors are not showing individually set colors using fillColor then they may be being set to a default widget parameter.

Try adding app:itemIconTint="@color/lime" to activity_main.xml to set a default color type for the widget icons.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:itemIconTint="@color/lime"
        app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>

VectorDrawable @ developers.android

lubi
  • 167
  • 13
2

Add this library to the Gradle to enable color vector drawable in old android Devices.

compile 'com.android.support:palette-v7:26.0.0-alpha1'

and re sync gradle. I think it will solve the problem.

Siddhartha Maji
  • 1,022
  • 8
  • 15
2

For my ImageButton, I used app:tint="@color/green" instead of android:tint

fullmoon
  • 8,030
  • 5
  • 43
  • 58
1

if you look to support old version pre lolipop

use the same xml code with some changes

instead of normal ImageView --> AppCompatImageView

instead of android:src --> app:srcCompat

here is example

<android.support.v7.widget.AppCompatImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:id="@+id/button"
        app:srcCompat="@drawable/ic_more_vert_24dp"
        android:tint="@color/primary" />

dont forget update your gradle as @ Sayooj Valsan mention

// Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
   }  
 }  

 compile 'com.android.support:design:23.4.0'

Notice To any one use vector dont ever ever never give your vector reference to color like this one android:fillColor="@color/primary" give its hex value .

Mina Fawzy
  • 20,852
  • 17
  • 133
  • 156
1

Go to you MainActivity.java and below this code
-> NavigationView navigationView = findViewById(R.id.nav_view);
Add single line of code -> navigationView.setItemIconTintList(null);
i.e. the last line of my code

I hope this might solve your problem.

public class MainActivity extends AppCompatActivity {

    private AppBarConfiguration mAppBarConfiguration;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        navigationView.setItemIconTintList(null);
David Buck
  • 3,752
  • 35
  • 31
  • 35
0

For those not using an ImageView, the following worked for me on a plain View (and hence the behaviour should replicate on any kind of view)

<View
    android:background="@drawable/ic_reset"
    android:backgroundTint="@color/colorLightText" />
Bonton255
  • 2,231
  • 3
  • 28
  • 44
0

If you want to change the color of an item vector icon you can use this:

android:iconTint="@color/color"
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Jaime2m1
  • 57
  • 5
0

If the vector asset is within a CardView, try card_view:tint="@color/secondary" within the ImageView. Note: Replace @color/secondary with your desired color.

ofa
  • 21
  • 1
  • 5
0

use

android:drawableTint="@color/primary"

in activity_main.xml

activity_main.xml

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
0

Here is the Kotlin version of Drawable Helper by Filipe

class DrawableHelper(var mContext: Context) {
    @ColorRes
    private var mColor = 0
    private lateinit var mDrawable: Drawable
    private lateinit var mWrappedDrawable: Drawable
    fun withDrawable(@DrawableRes drawableRes: Int): DrawableHelper {
        mDrawable = getDrawable(mContext, drawableRes)!!
        return this
    }

    fun withDrawable(drawable: Drawable): DrawableHelper {
        mDrawable = drawable
        return this
    }

    @SuppressLint("ResourceType")
    fun withColor(@ColorRes colorRes: Int): DrawableHelper {
        mColor = ContextCompat.getColor(mContext, colorRes)
        return this
    }

    @SuppressLint("ResourceAsColor")
    fun tint(): DrawableHelper {
        mWrappedDrawable = DrawableCompat.wrap(mWrappedDrawable)
        DrawableCompat.setTint(mWrappedDrawable, mColor)
        DrawableCompat.setTintMode(mWrappedDrawable, PorterDuff.Mode.SRC_IN)
        return this
    }

    fun applyToBackground(view: View) {
        view.background = mWrappedDrawable
    }

    fun applyTo(imageView: ImageView) {
        imageView.setImageDrawable(mWrappedDrawable)
    }

    fun applyTo(menuItem: MenuItem) {
        menuItem.icon = mWrappedDrawable
    }

    fun get(): Drawable {
        return mWrappedDrawable
    }

    companion object {
        fun withContext(context: Context): DrawableHelper {
            return DrawableHelper(context)
        }
    }
}
binrebin
  • 357
  • 4
  • 16
  • there's a mistake in `tint()` method where instead of: `mWrappedDrawable = DrawableCompat.wrap(mWrappedDrawable)` you should have: `mWrappedDrawable = DrawableCompat.wrap(mDrawable)` – ursimon Jun 01 '22 at 12:20