On newer Android versions, the following code:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="oval"> <solid android:color="#bdbdbd" /> <size android:width="60dp" android:height="60dp" /> </shape> </item> <item android:drawable="@drawable/ic_library_books_black_24dp" android:gravity="center" android:width="40dp" android:height="40dp" > </item> </layer-list>
produces this flawlessly:
However, earlier Android versions (API 16 and 19, from what I've tested) do not like this at all and I get
E/AndroidRuntime: FATAL EXCEPTION: main Process: package.app, PID: 11490 android.view.InflateException: Binary XML file line #26: Error inflating class ImageView
upon inflation. I have used app:srcCompat
for all my ImageViews so there is no problem there.
Standard Vector Drawables also work fine, but when placed in a layer-list
they cause mayhem. Are there any workarounds?
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.
Android Studio includes a tool called Vector Asset Studio that helps you add material icons and import Scalable Vector Graphic (SVG) and Adobe Photoshop Document (PSD) files into your project as vector drawable resources.
Layer list. A LayerDrawable is a drawable object that manages an array of other drawables. Each drawable in the list is drawn in the order of the list—the last drawable in the list is drawn on top.
The width/height attributes for the vector drawable in your layer-list are only supported in API 23 (Marshmallow) and higher. If you look at your layer-list drawable in the Android Studio editor, these attributes should have yellow blocks around them along with a warning that this won't work reliably on older devices.
But I think you can get rid of the warning and achieve the same centering effect like this:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="oval"> <solid android:color="#bdbdbd" /> <size android:width="60dp" android:height="60dp" /> </shape> </item> <item android:drawable="@drawable/ic_library_books_black_24dp" android:top="10dp" android:bottom="10dp" android:left="10dp" android:right="10dp"> </item> </layer-list>
I tested this on an old API 15 phone and it worked fine. I hope this works for you too.
In a previous version of this answer, I'd advised against using vectorDrawables.useSupportLibrary = true
with layer lists, because it caused crashes. However, I've recently learned about a workaround that seems to fix the crash (while avoiding the fat auto-generated png files that @android developer correctly mentioned). Here's a summary of what needs to be done for it to work correctly:
Be sure to use srcCompat in your xml.
<android.support.v7.widget.AppCompatImageView android:layout_width="wrap_content" android:layout_height="wrap_content" app:srcCompat="@drawable/layer_list_with_svg" />
Add 'vectorDrawables.useSupportLibrary' to app/build.gradle
android { defaultConfig { vectorDrawables.useSupportLibrary = true } }
Add 'setCompatVectorFromResourcesEnabled(true)' to onCreate
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); setContentView(R.layout.activity_main); }
As a more knowledgable person explained it to me, this has to do with how Android loads up the compat vector drawables. If you're using vectorDrawables.useSupportLibrary = true
then image views will load up VectorDrawableCompat
drawables when you use app:srcCompat
. When your layer list drawable is inflated, there's no way for it to figure out how to create those referenced vector drawables. But if you turn on setCompatVectorFromResourcesEnabled
it will try to hook the vector drawable loading in at a much lower level than image views and their app:srcCompat
attribute, so it's then able to figure out how to load the vector drawables referenced in the layer list.
This answer draws on the article AppCompat - Age of the Vectors by Chris Banes(who works on the Support Library). For this question we're looking specifically at the section titled The 'magic' way.
The crash you're experiencing is because the Support Library only allows some ways of using VectorDrawables by default, and layer-list is not one of them.
There is a specific code block you can add to the top of your Activity to enable other VectorDrawable
use such as <layer-list>
:
static { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }
Note: the linked article contains a typo in this method name, using "FromSources", it should be "FromResources" as shown above.
You would need to add this to each Activity where you want to use such drawables, or perhaps include it in a BaseActivity class that your other Activities extend from.
Per the article, this should mean the following will now work:
DrawableContainers which reference other drawables resources which contain only a vector resource.
...StateListDrawable...InsetDrawable, LayerDrawable, LevelListDrawable and RotateDrawable.
It should be noted though, this method is heavily couched with the word 'may', this may work, and it is not enabled by default, so be aware and check it's really working for you!
Now there's actually another dimension to this question, credit to other users Selim Ajimi and Rapunzel Van Winkle for addressing this in their answers. <layer-list>
has some different behaviour between the API's, in particular the width
and height
attributes of your <item>
only being supported in API 23+. This is not the cause of your crash, nor will it cause your app to crash, but will mean that your image will not look as intended once you have it functioning in earlier APIs.
The suggestion from Rapunzel Van Winkle does indeed seem to be a good way to position the drawable correctly across APIs (tested on API 16 and 24):
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="oval"> <solid android:color="#bdbdbd" /> <size android:width="60dp" android:height="60dp" /> </shape> </item> <item android:drawable="@drawable/ic_library_books_black_24dp" android:top="10dp" android:bottom="10dp" android:left="10dp" android:right="10dp" > </item> </layer-list>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With