Change fill color on vector asset in Android Studio
Asked Answered
S

18

218

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

Stoeber answered 3/10, 2015 at 16:44 Comment(0)
D
418

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" />
Dandify answered 3/10, 2015 at 20:4 Comment(13)
tinting only works on 21+ devices, do you have any suggestion for pre-lollipop devicesWilburwilburn
android:tint works on all android versions since APIv1. What you mean is drawableTint.Dandify
android:tint must be after android:srcMaggiore
What about drawableLeft in Button?Newsstand
@Wilburwilburn 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)Heartbreaking
What if I'm using this asset in a menu Item? @HeartbreakingNyssa
@MichaelObi Not sure, just try on both pre-SDK21 and SDK21+Heartbreaking
you must use app:srcCompat instead of android:src for supporting pre-lolipop devicesElastin
@MichaelObi This is the same question I had. There is no android:tint attribute for an item in a menu .xml file.Allochthonous
@Maggiore Why does tint have to go after src? That makes no sense, attributes are loaded in the order that Java code is written... See android.googlesource.com/platform/frameworks/base/+/master/core/… (tint) and android.googlesource.com/platform/frameworks/base/+/master/core/… (src) Am I missing something?Inherited
@Inherited 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.Maggiore
@Dandify 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?Vikki
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.gradleTheir
O
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"/>

Otway answered 5/11, 2015 at 19:25 Comment(8)
This should be the accepted answer! @color references don't work in vectors pre-Lollipop (so vector -> PNG conversion) code.google.com/p/android/issues/detail?id=186431Heartbreaking
@color references can now be used for the fillColor attribute for all Android versions, however it does not support color state lists.Neri
It looks like the way to do vector state lists is with AnimatedStateListDrawablesPrepotency
@Neri what do I have to enable it? Doesnt seem to work for meOtway
@Heartbreaking 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 colorDosage
@AntonMakov yes, ofc its only for static thingsOtway
@PieterAelse, I'm able to refer color references and it's working fine API 19. e.g. android:fillColor="@color/icon_color"Sled
does not work iven when setting color directly. Still white.Clamant
S
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);
Seng answered 29/1, 2016 at 12:6 Comment(7)
Hi Filipe, thanks for your answer. Do you have a library, snipped code github where we can see the license? thanks :)Limnetic
Nope Vicent, no license at all. The solution it's so simple that I guess the Builder pattern used here isn't necessary. But anyone can be benefit of this solution and use without license.Seng
Great answer! Works exactly like I needFarm
@VincentD. The SO web page footer says "user contributions licensed under cc by-sa 3.0 with attribution required"Hemia
It worked for me with some changes. Thank you for your help.Brnaba
A 1° vez que vejo um brasileiro no StackOverflow e o cara me salva haha Vlw velho me poupou um bom tempo!Here
This should be the accepted answer. Worked perfectly!Sundries
S
47

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));
Scyros answered 25/7, 2016 at 13:56 Comment(3)
getColor() is deprecatedCotyledon
How to use it for TextView's drawable*** ?Pudgy
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.Cassiopeia
G
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.

Gayegayel answered 29/11, 2015 at 20:2 Comment(0)
C
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 
Curitiba answered 16/7, 2017 at 18:31 Comment(1)
Just an update. Nowadays the AppCompatImageView is under androidx.appcompat.widget.AppCompatImageViewCuller
N
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'
Nert answered 9/6, 2016 at 23:44 Comment(1)
The question is "how to change vector fill colour", not "how to use vector asset"Elastin
C
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>
Consummation answered 1/2, 2022 at 7:7 Comment(2)
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.Iey
Thanks a lot! This is the easiest way to change the color. android:tint = "//Your Color Code//"Eisenach
D
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

Drona answered 9/9, 2017 at 23:59 Comment(1)
In Android studio 3.6 change in svg xml this field: android:fillColor="#FFFFC400"Kissiah
H
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.

Headphone answered 10/7, 2017 at 7:35 Comment(0)
B
2

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

Bandeau answered 8/8, 2021 at 17:40 Comment(0)
M
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 .

Micromillimeter answered 15/3, 2017 at 9:51 Comment(1)
why never use @color for fillcolor ?Sing
P
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);
Potato answered 16/8, 2020 at 11:53 Comment(0)
F
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" />
Florettaflorette answered 15/2, 2020 at 6:17 Comment(0)
F
0

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

android:iconTint="@color/color"
Fafnir answered 8/4, 2021 at 10:10 Comment(1)
Only API 26 and higherBolin
L
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.

Lip answered 10/7, 2021 at 8:21 Comment(0)
P
0

use

android:drawableTint="@color/primary"

in activity_main.xml

activity_main.xml

Pitchdark answered 12/12, 2021 at 8:59 Comment(0)
W
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)
        }
    }
}
Wager answered 14/4, 2022 at 18:32 Comment(1)
there's a mistake in tint() method where instead of: mWrappedDrawable = DrawableCompat.wrap(mWrappedDrawable) you should have: mWrappedDrawable = DrawableCompat.wrap(mDrawable)Unsphere

© 2022 - 2024 — McMap. All rights reserved.