34

I was using the support vector drawables added in Support Library 23.2 along with AppCompat. I was using vector drawables both with app:srcCompat and inside a StateListDrawable so I could use them with android:drawableLeft for my TextView.

Since upgrading to the 23.3.0 version of AppCompat, only the vectors in app:srcCompat are working. Whenever I reference it the other way I get

FATAL EXCEPTION: main
 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.package.name/.MainActivity}: android.view.InflateException: Binary XML file line #8: Error inflating class Button
 ...
 Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class Button
 ...
 Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line #14: invalid drawable tag vector
  at android.graphics.d

What changed that now causes my support vector drawables to fail in some cases?

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • finally I don't get it. if I wanna use vector just remove vectorDrawables.useSupportLibrary = true and using app:srcCompat or ordinari android:src ? – Mahdi May 08 '16 at 15:07
  • See my answer here: http://stackoverflow.com/a/37864531/3870932 – Rich Luick Jun 16 '16 at 16:24

3 Answers3

43

Update: They enable it again in Support Library 23:

For AppCompat users, we’ve added an opt-in API to re-enable support Vector Drawables from resources (the behavior found in 23.2) via AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); - keep in mind that this still can cause issues with memory usage and problems updating Configuration instances, hence why it is disabled by default.

Check this link: 23.4.0 available now
-----------------------------------------------------------

As per the release announcement for Android Support Library 23.3:

For AppCompat users, we’ve decided to remove the functionality which let you use vector drawables from resources on pre-Lollipop devices due to issues found in the implementation in version 23.2.0/23.2.1 [ https://code.google.com/p/android/issues/detail?id=205236, https://code.google.com/p/android/issues/detail?id=204708 ]. Using app:srcCompat and setImageResource() continues to work.

So this is an expected behavior change. You'll have to use non-vector graphics for any case not handled by srcCompat.

If you'd like to continue to use vectors prior to API 21, you can remove the line

vectorDrawables.useSupportLibrary = true

(or the equivalent if you using the 1.5 Gradle plugin as shown in the 23.2 blog post).

This will cause Android Studio to generate PNGs at compile time for apps with a minSdkVersion less than API 21 while using your vectors on API 21+ devices, allowing you to keep the same code as with 23.2.1 at the cost of additional APK size.

Felipe Conde
  • 2,024
  • 23
  • 26
ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • 1
    can i use it with android gradle plugin 2.0.0? – Arnav M. Apr 08 '16 at 04:12
  • @ArnavM. the version of Gradle Plugin does not change anything (only how you enable support vector drawables) – ianhanniballake Apr 08 '16 at 04:43
  • @IanLake the InstantRun feature requires gradle 2.1.0-alpha5 .. can't use generatedDencities with that? – Arnav M. Apr 08 '16 at 04:51
  • So basically app:srcCompat is useless now, since if we disable the vector drawables support library we end up with all the vectors in PNG anyway. What about all the "drawableStart/drawableEnd/etc" benefits, they are now gone, and it looks impossible to mix vector and non-vector assets in XML layouts due to this regression which crashes the app if a drawable has a vector. – Adrian Crețu Apr 08 '16 at 16:15
  • 4
    @AdrianCrețu - well, if all you are using support vectors for is through srcCompat or at runtime with `VectorDrawableCompat.create()`, then you can continue to use support vectors prior to Lollipop. There's a [data binding technique](https://plus.google.com/+LisaWrayZeitouni/posts/MxJ2PVpBMbf) that seeks to restore this functionality by using `VectorDrawableCompat.create()` under the covers. – ianhanniballake Apr 08 '16 at 16:33
  • @ianhanniballake - this implies that the developer should use srcCompat and have vector drawables only for these cases, while attributes like drawableLeft (or even src with a StateList) NEED to only use PNG drawables. Because PNGs are usually generated from vectors, we therefore need to disable the vector support lib, so in turn srcCompat is no longer useful, since we'll have PNGs for all drawables anyway. How is this useful then? I'm asking for the pre-Lollipop use-case, ofcourse. – Adrian Crețu Apr 08 '16 at 17:07
  • @AdrianCrețu - Yep, the tooling unfortunately is an all or nothing thing when it comes to generating PNGs from vectors as part of your build. Of course, you could use vectors for only the srcCompat cases and manually generated PNGs for non-srcCompat cases and skip the Android Studio generation of PNGs entirely, allowing you to keep `useSupportLibrary = true` and only use vectors where possible. – ianhanniballake Apr 08 '16 at 17:25
  • @ianhanniballake I removed vectorDrawables.useSupportLibrary = true but app crash when using srcCompat for vector graphics, but works with ordinary android:drawable ! why this happens? – Mahdi May 08 '16 at 15:03
  • 1
    @Kenji: if you've removed useSupportLibrary, then you don't need srcCompat either. Just use src – ianhanniballake May 08 '16 at 15:58
  • Should it work with keyboard icons (android:keyIcon)? – Maxim G Jul 08 '16 at 19:25
  • Simply use `AppCompatImageView` instead of `ImageView`. Problem solved. No need to keep pngs for lower versions. Even `srcCompat` is not needed. – Harish Gyanani Dec 22 '16 at 05:43
  • @HarishGyanani - if you are using AppCompat, any `ImageView` in your layouts will automatically be replaced with `AppCompatImageView`. That is precisely why `app:srcCompat` and `setImageResource()` work. – ianhanniballake Dec 22 '16 at 05:45
  • I can show you so many cases where images are not shown even if `srcCompat` is used and other things have been done. (like vectorDrawables.useSupportLibrary = true and AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); ). `AppCompatImageView` always work. – Harish Gyanani Dec 22 '16 at 05:49
  • @HarishGyanani - then you are using the wrong layout inflater. Always use `LayoutInflater.from(activityContext)` or `activity.getLayoutInflater()`. – ianhanniballake Dec 22 '16 at 05:50
  • @ianhanniballake I got your point and found out my problem. thanks – Harish Gyanani Dec 22 '16 at 06:39
18

VectorDrawable support for pre-Lollipop was added in Support Library 23.2.0, then partially removed in 23.3.0. In 23.4.0 and above (at least 25.1.0), that removed part is back but behind an optional flag (because it comes with a price).

To sum up: in Support Library 23.4.0 to at least 25.1.0, you can get VectorDrawable to work in some cases.

I have made this diagram to help.

VectorDrawable cheatsheet

David Ferrand
  • 5,357
  • 1
  • 33
  • 43
5

To use vectors as compoundDrawables ( ex. for textview ) without using

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

which leads to documented high memory usage, just inflate the vector using

Drawable drawable = AppCompatResources.getDrawable( getContext(), R.drawable.vector_resID );
if( drawable != null ) drawable.setBounds( 0, 0, iconSize, iconSize );
TextViewCompat.setCompoundDrawablesRelative( textView, null, null, drawable, null);

This is the way the navDrawer works

nGL
  • 333
  • 3
  • 12
  • You can also use `TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds()`, then you don't need to set the bounds yourself. – ubuntudroid Jun 24 '21 at 16:07