Change fillColor of a vector in android programmatically
Asked Answered
F

9

56

I want to edit the fill Color of a vector-file in Android programmatically.

In the xml-file I can set my color with the attribute android:fillColor but I want to change the color in runtime.

Any examples for that? Thanks.

Fountainhead answered 14/10, 2015 at 13:37 Comment(4)
Hi.. did you find the solution??.. as i am facing the same issue..Downstairs
You can change the color from the vector file in XML with android:tint, in runtime with setColorFilterFountainhead
https://mcmap.net/q/57553/-android-how-to-set-stroke-color-for-vector-drawable-programmaticallySidelong
The blog with complete answer emmav.me/posts/2015-nov-29-dynamic-svg-coloursWellintentioned
D
54

This is exactly what you need. Credits to @emmaguy, the author of the post. I just added the full support of Support Library 23.4+, which enables you to stop generating pngs at runtime:

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

And if this line is set on your Activity's or Application's onCreate:

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

You can use your SVGs not only with srcCompat but also with other attributes such as drawableLeft, background, etc. in TextView, ToggleButton and so on. It also works if used on selectors.

Note: I modified the code to use VectorDrawableCompat.create instead of ResourcesCompat.getDrawable. Otherwise it would not work and throw org.xmlpull.v1.XmlPullParserException: Binary XML file line #2: invalid drawable tag vector.


Medium post content:

First, we create attributes for the two kinds of bauble, so we can change their colours:

<declare-styleable name="ChristmasTree">
    <attr name="bauble_round" format="color" />
    <attr name="bauble_small" format="color" />
</declare-styleable>

Then, in the VectorDrawable, set the parts we want to dynamically change to use these attributes:

<path
    android:fillColor="?attr/bauble_round"
    android:pathData="...." />
<path
    android:fillColor="?attr/bauble_small"
    android:pathData="...." />
...

Create themes and set the colours you want to use:

<style name="UpdatedScene" parent="DefaultScene">
    <item name="bauble_round">#db486e</item>
    <item name="bauble_small">#22c7f7</item>
</style>

<style name="DefaultScene">
    <item name="bauble_round">#fec758</item>
    <item name="bauble_small">#f22424</item>
</style>

Use the drawable in an ImageView:

final ContextThemeWrapper wrapper = new ContextThemeWrapper(this, R.style.DefaultScene);
final Drawable drawable = VectorDrawableCompat.create(getResources(), R.drawable.christmas, wrapper.getTheme());
imageView.setImageDrawable(drawable);

That’s it! When you want to change the colours, simply set a different theme and your drawable will update. See the GitHub repo for a full sample.

Deicer answered 17/7, 2016 at 4:59 Comment(6)
you can get the Drawable with color from attr with this also: ResourcesCompat.getDrawable(getResources(), R.drawable.ic, getTheme())Underwent
this is fine for small number of states but what if I want to update after each frame during animation? eg. as per #2615045Undefined
Fyi: also read the docs carefully setcompatvectorfromresourcesenabled "This feature defaults to disabled, since enabling it can cause issues with memory usage.." Happy coding.Fought
This won't work for API < 21, since you can't use values like ?attr/colorPrimary on the fillColor attribute...Colorado
How do we do the last step "Simply set a different theme" programmatically?Self
@AlanNelson you can achieve that by doing, for example: final Resources.Theme theme = getResources().newTheme(); theme.applyStyle(R.style.BaubleRound, false);Deicer
O
26

If you want to change the whole color, you could apply a PorterduffColorFilter. But this does not work for a single <path>. Only for the whole drawable.

public void applyThemeToDrawable(Drawable image) {
    if (image != null) {
        PorterDuffColorFilter porterDuffColorFilter = new PorterDuffColorFilter(Color.BLUE,
                PorterDuff.Mode.SRC_ATOP);

        image.setColorFilter(porterDuffColorFilter);
    }
}

VectorDrawable extends the Drawable class. See Docs

Outpoint answered 14/10, 2015 at 13:51 Comment(4)
Is there any other solution to color only a single <path>Fountainhead
Found this answer. So I guess you can not change single path color programmatically. At least not to completely random color. Only for a fixed set, defined as XML transitionsOutpoint
You can always split the paths in separate images, overlay those views and then set filters on individual views. Not ideal in all situation but for some it's fine.Tudela
This is what we do now, but did not think of at the time the question was asked. But keep in mind, that this will double the memory used, everytime you split. Not a big deal for most of the time, but sometimes it could matter.Outpoint
K
18

add setColorFilter() method to your image content vector (is added in api level 8) like this:

imgshare = (Imageview) findviewbyId(R.id.imageshare);
imgshare.setColorFilter(color);
Kimmy answered 17/5, 2017 at 5:13 Comment(1)
For color, just make sure not to use R.color.value directly - need to call getColor(R.color.value)Lipstick
T
1

button.setColorFilter(getResources().getColor(R.color.YOUR_COLOR));

example:

dislikeBtn.setColorFilter(getResources().getColor(R.color.grey));

Tay answered 9/6, 2020 at 15:23 Comment(0)
U
1

None of these answers worked for changing the color of a vector path inside a drawable at runtime. In fact, I still didn't figure that out, but I think this answer would help a lot of people who are just trying to create and paint a simple shape at runtime.

I was trying to create a custom border Mvvm binding to customise the border & fill colors of a Button at runtime. For a while I was trying to modify an Android drawable to achieve this but found out that wasn't possible. Eventually I figured out how to do this with GradientDrawable.

I'm using Xamarin.Android in C# so it does look slightly different from Java.

GradientDrawable gd = new GradientDrawable();
gd.SetColor(Color.Red);
gd.SetCornerRadius(10);

gd.SetStroke(3, Color.White);

view.Background = gd;
Undercroft answered 1/10, 2020 at 18:32 Comment(0)
M
1

Here is what worked for me:

VectorDrawableCompat vd = VectorDrawableCompat.create(getResources(),your_drawable_res_id,getContext().getTheme());
vd.setTint(Color.red);
imageview.setImageDrawable(vd);
Madura answered 4/9, 2023 at 17:18 Comment(0)
B
0

Just use:

imageView.setColorFilter(ContextCompat.getColor(context, R.color.white), PorterDuff.Mode.SRC_IN)
Birkle answered 23/8, 2023 at 15:50 Comment(0)
S
-1

To change the colors of vectors, don't change the fillColor. Instead, programmatically change the tint which will do the same thing and save you a lot of time! See this answer here.

Self answered 6/4, 2021 at 21:29 Comment(0)
P
-1

To people looking for an answer when your vector have 2 or more <path> or you just want to keep your stroke color's different than fill color:

I don't think there is a way to programmatically change only the fillColor of Vector while ignoring the strokeColor (tint will modify both)

I've made a workaround by creating 3 copies of my Vector asset with different colors defined in .xml, then in kotlin I've just set proper copy of that Vector asset. For example: view.setBackgroundResource(R.drawable.myVectorColor1)

view.setBackgroundResource(R.drawable.myVectorColor2)

Phrensy answered 15/7, 2021 at 13:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.