app:srcCompat
with ImageView
allows for backward compatible use of vector drawables. But how can you use them with other View
s besides ImageView
? For example, the TextView
attributes like android:drawableLeft
.
Also using the vector drawable as an android:icon
with MenuItem
caused a crash with the following exception:
Fatal Exception: android.view.InflateException: Binary XML file line #2: Error inflating class <unknown> at android.view.LayoutInflater.createView(LayoutInflater.java:626) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:702) at android.view.LayoutInflater.inflate(LayoutInflater.java:470) at android.view.LayoutInflater.inflate(LayoutInflater.java:398) at android.support.v7.view.menu.MenuItemImpl.setActionView(MenuItemImpl.java:621) at android.support.v7.view.menu.MenuItemImpl.setActionView(MenuItemImpl.java:40) at android.support.v4.view.MenuItemCompat.setActionView(MenuItemCompat.java:310) at android.support.v7.view.SupportMenuInflater$MenuState.setItem(SupportMenuInflater.java:465) at android.support.v7.view.SupportMenuInflater$MenuState.addItem(SupportMenuInflater.java:479) at android.support.v7.view.SupportMenuInflater.parseMenu(SupportMenuInflater.java:196) at android.support.v7.view.SupportMenuInflater.inflate(SupportMenuInflater.java:118) at com.example.niceapp.context.main.MainActivity.onCreateOptionsMenu(MainActivity.java:101) at android.app.Activity.onCreatePanelMenu(Activity.java:2578)
With Support Library 23.2.0, how can this issue be addressed?
Update 2: They have added an option to enable it again in Support Library 23.4.0:
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() - keep in mind that this still can cause issues with memory usage and problems updating Configuration instances, hence why it is disabled by default.
Update: This no longer works starting from version 23.3.0
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.
From Android Developers Google+ post
Using AppCompat and app:srcCompat is the most foolproof method of integrating vector drawables into your app.
That quote is from the official blogpost for the release of version 23.2.0 of the Support Library.
The post also mentions the following:
You’ll find directly referencing vector drawables outside of
app:srcCompat
will fail prior to Lollipop. However,AppCompat
does support loading vector drawables when they are referenced in another drawable container such as aStateListDrawable
,InsetDrawable
,LayerDrawable
,LevelListDrawable
, andRotateDrawable
. By using this indirection, you can use vector drawables in cases such asTextView
’sandroid:drawableLeft
attribute, which wouldn’t normally be able to support vector drawables.
This translates to the steps below:
Step 1:
Create or import a vector resource which you require for the app. For example, one can create a vector drawable for the search icon and name it ic_action_search_vector.xml
Step 2:
Create another proxy drawable resource for the vector drawable previously created. Say, for the previous ic_action_search_vector.xml
, ic_action_search.xml
can be created as a simple StateListDrawable
which could contain the lines below:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_action_search_vector"/> </selector>
This step can be skipped if you have referenced the vector drawable from another drawable resource which you will use with your View.
Step 3:
Use the drawable resource (here, ic_action_search.xml
) that refers to the vector drawable (ic_action_search_vector.xml
) instead of the vector drawable directly. For a menu, it would look like:
<item android:id="@+id/search" android:title="@string/search" android:icon="@drawable/ic_action_search" app:showAsAction="always"/>
This is the solution to that problem!
For AppCompat version 23.3.0 where no work solution via selector XML (razzledazzle's accepted answer) we can do this by programmatically:
activity_main.xml
<android.support.v7.widget.AppCompatImageButton android:id="@+id/btnEnter" />
MainActivity.java
AppCompatImageButton image = (AppCompatImageButton) findViewById(R.id.btnEnter); if (image != null) { VectorDrawableCompat vcAccept = VectorDrawableCompat.create(getResources(), R.drawable.vc_accept, getTheme()); VectorDrawableCompat vcAcceptWhite = VectorDrawableCompat.create(getResources(), R.drawable.vc_accept_white, getTheme()); StateListDrawable stateList = new StateListDrawable(); stateList.addState(new int[]{android.R.attr.state_focused, -android.R.attr.state_pressed}, vcAccept); stateList.addState(new int[]{android.R.attr.state_focused, android.R.attr.state_pressed}, vcAcceptWhite); stateList.addState(new int[]{-android.R.attr.state_focused, android.R.attr.state_pressed}, vcAcceptWhite); stateList.addState(new int[]{}, vcAccept); image.setImageDrawable(stateList); }
This code is equivalent for this selector xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/vc_accept" /> <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/vc_accept_white" /> <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/vc_accept_white" /> <item android:drawable="@drawable/vc_accept" /> </selector>
If the vector drawable is not shown using API 23, you'll need to convert the VectorDrawable
to a regular Drawable
first. If you want to use setCompoundDrawablesWithIntrinsicBounds
you'll need to do this, but for StateListDrawable I didn't need to.
Drawable icon; if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { icon = VectorDrawableCompat.create(getResources(), R.drawable.vc_icon, getContext().getTheme()); } else { icon = getResources().getDrawable(R.drawable.vc_icon, getContext().getTheme()); }
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