Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically tint a Support Vector

Tags:

Android Studio version 2.1, gradle version 2.1.0, please correct me if you spot any misinterpretations :)

I am confused about support vectors in the support library 23.3.0. Specifically what I would like to do is tint an image button programmatically, whose src is defined is a vector drawable. From what I can tell this is not possible on pre-lollipop now.

I have read several related posts about the changes: 23.2.0 announcement and changes:

As of Android Support Library 23.3.0, support vector drawables can only be loaded via app:srcCompat or setImageResource().

Does the above mean that vector xmls can only be used pre-Lollipop via srcCompat or setImageResource(), and therefore cannot be dynamically tinted?

Here is my basic image button:

<ImageButton     android:id="@+id/nav_header_exit_community_button"     android:layout_width="48dp"     android:layout_height="48dp"     android:layout_alignParentTop="true"     android:layout_alignParentRight="true"     android:background="@null"/> 

Works on Lollipop and above only:

    Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);     DrawableCompat.setTint(bg, headerTitleColor);     exitButton.setImageDrawable(bg); 

Attempting this pre-lollipop throws: android.content.res.Resources$NotFoundException: File res/drawable/ic_exit_to_app_24dp.xml from drawable resource ID #0x7f0200bf

Also works on Lollipop and above only

    Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);     DrawableCompat.setTint(bg, headerTitleColor);     exitButton.setImageResource(R.drawable.ic_exit_to_app_24dp); 

This throws the same error on pre-Lollipop.

However if I remove vectorDrawables.useSupportLibrary = true as pointed out by Ian Lake here, with the intent of having the build tools auto-generate pngs for pre-Lollipop devices, the pngs do not tint on pre-lollipop, so I'm back to square one.

I have also tried specifying the vector via srcCompat and retrieving it programmatically but I don't think I've been able to achieve that, even though it works on post-Lollipop if the vector is specified using src instead.

So the situation for 23.3.0 seems to be:

  • Post-Lollipop: src and srcCompat accept vectors, only src can be retrieved from the view as a drawable for tinting programmatically. Referencing vectors in code is possible using getDrawable, and they can be tinted.

  • Pre-Lollipop: srcCompat only can accept vectors, cannot be retrieved programmatically from the view for tinting. setImageResource can accept vectors, but only if vectorDrawables.useSupportLibrary = false, and tinting does not work. Similarly referencing vectors in code is not possible unless vectorDrawables.useSupportLibrary = false and tinting does not work.

Working on all versions using pngs:

   Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_nav_exit_community);    DrawableCompat.setTint(bg, headerTitleColor);    exitButton.setImageDrawable(bg); 

Addendum:

This technique also works on post-Lollipop, but like the others on pre-Lollipop I get the drawable, but no tinting:

    Drawable bg = VectorDrawableCompat.create(a.getResources(), R.drawable.ic_exit_to_app_24dp, null);     DrawableCompat.setTint(bg, headerTitleColor);     exitButton.setImageDrawable(bg); 

KIND OF SOLUTION:

Thanks to John's answer so far the only fool-proof way I can come up with to tint a support vector is to set a color filter on it - this means the DrawableCompat.setTint() function is seemingly not functional for me if the drawable in question is a support vector. I'm not sure if this is a legit bug, expected behavior or if I'm just doing something wrong!

Here is the solution I'm going with for the moment:

    Drawable bg;     if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {         bg = VectorDrawableCompat.create(a.getResources(), R.drawable.ic_exit_to_app_24dp, null);         exitButton.setColorFilter(headerTitleColor, PorterDuff.Mode.MULTIPLY);     }     else {         bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);         DrawableCompat.setTint(bg, headerTitleColor);     }     exitButton.setImageDrawable(bg); 
like image 402
Daniel Wilson Avatar asked Apr 27 '16 18:04

Daniel Wilson


People also ask

What is VectorDrawable?

A VectorDrawable is a vector graphic defined in an XML file as a set of points, lines, and curves along with its associated color information. The major advantage of using a vector drawable is image scalability.

How do I change vector icon color in android programmatically?

Tere is need to Change fillColor of a vector drawable in android programmatically, you can edit fill Color of a vector-file in Android programmatically using DrawableCompat. setTint() method which change tint color of whole vector drawable. Here, ImageView is set with drawable vector icon of black color.


1 Answers

first of all you should use VectorDrawableCompat#create, once you have your Drawable you have to call DrawableCompat#wrap:

Potentially wrap drawable so that it may be used for tinting across the different API levels, via the tinting methods in this class.

so your code would look like this:

ImageView iv = .... Drawable d = VectorDrawableCompat.create(getResources(), R.drawable.ic_exit_to_app_24dp, null); d = DrawableCompat.wrap(d); DrawableCompat.setTint(d, headerTitleColor); iv.setImageDrawable(d); 
like image 174
pskink Avatar answered Sep 27 '22 20:09

pskink