Как использовать векторные чертежи с представлением помимо ImageView с srcCompat?
app:srcCompat
с ImageView
допускает обратное совместимое использование векторных чертежей. Но как вы можете использовать их с другими View
помимо ImageView
? Например, атрибуты TextView
, такие как android:drawableLeft
.
Также использование вектора, выведенного как android:icon
с MenuItem
, вызвало сбой со следующим исключением:
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)
С поддержкой библиотеки 23.2.0, как решить эту проблему?
Ответы
Ответ 1
Для AppCompat версии 23.3.0, где нет решения для работы с помощью селектора XML (принятый ответ razzledazzle), мы можем сделать это программным путем:
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);
}
Этот код эквивалентен для этого селектора 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>
UPDATE
Если векторный чертеж не показан с использованием API 23, вам нужно сначала преобразовать VectorDrawable
в обычный Drawable
. Если вы хотите использовать setCompoundDrawablesWithIntrinsicBounds
, вам нужно это сделать, но для StateListDrawable мне не нужно было.
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());
}
Ответ 2
Обновление 2: они добавили возможность включить его снова в библиотеке поддержки 23.4.0:
Для пользователей AppCompat мы добавили API-интерфейс для повторного включения поддержки векторных чертежей из ресурсов (поведение, обнаруженное в 23.2), с помощью AppCompatDelegate.setCompatVectorFromResourcesEnabled( ) - имейте в виду, что это все еще может вызвать проблемы с использованием памяти и проблемы с обновлением экземпляров Configuration, поэтому почему она по умолчанию отключена.
Обновление:
Это больше не работает начиная с версии 23.3.0
Для пользователей AppCompat мы решили удалить функции, которые позволяют использовать векторные чертежи из ресурсов на устройствах, предшествующих Lollipop из-за проблем, обнаруженных при реализации в версии 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]. Использование приложения: srcCompat и setImageResource() продолжает работать.
От анонс разработчиков Google+ в Google+
Использование AppCompat и приложения: srcCompat - самый надежный способ интеграции векторных чертежей в ваше приложение.
Эта цитата из официального blogpost для выпуска версии 23.2.0 в Библиотеке поддержки.
В сообщении также упоминается следующее:
Вы найдете прямое обращение к векторным чертежам вне app:srcCompat
, которые не будут выполняться до Lollipop. Тем не менее, AppCompat
поддерживает загрузку векторных векторов, когда они ссылаются в другом контейнере, например, StateListDrawable
, InsetDrawable
, LayerDrawable
, LevelListDrawable
и RotateDrawable
. Используя эту косвенность, вы можете использовать векторные чертежи в таких случаях, как атрибут TextView
s android:drawableLeft
, который обычно не сможет поддерживать векторные чертежи.
Это приводит к следующим шагам:
Шаг 1:
Создайте или импортируйте векторный ресурс, который вам нужен для приложения. Например, можно создать вектор, подходящий для значка поиска, и назовите его ic_action_search_vector.xml
Шаг 2:
Создайте другой ресурс, который можно использовать для прокси-сервера, для созданного ранее вектора. Скажем, для предыдущего ic_action_search_vector.xml
, ic_action_search.xml
может быть создан как простой StateListDrawable
, который может содержать следующие строки:
<?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>
Этот шаг можно пропустить, если вы указали вектор, который можно извлечь из другого ресурса, который вы будете использовать с вашим представлением.
Шаг 3:
Используйте ресурс, который можно вытащить (здесь, ic_action_search.xml
), который ссылается на векторный drawable (ic_action_search_vector.xml
) вместо прямого преобразования вектора. Для меню это будет выглядеть так:
<item android:id="@+id/search"
android:title="@string/search"
android:icon="@drawable/ic_action_search"
app:showAsAction="always"/>
Это решение этой проблемы!
Ответ 3
векторные образы можно использовать pre-Lollipop в других местах, чем app:srcCompat
, но он поставляется с ценой.
Я сделал эту диаграмму, чтобы помочь (действителен для библиотеки поддержки 23.4.0 - не менее - 25.1.0).
![VectorDrawable cheatsheet]()
Ответ 4
Вы можете добавить Vector Drawable в TextView программно. Используйте VectorDrawableCompat для добавления drawableLeft/drawableRight/drawableTop/drawableBottom/drawableStart/drawableEnd.
Шаги:
я. Если TextView находится внутри Activity:
TextView tvUserName= (TextView)findViewById(R.id.et_username_or_email);
VectorDrawableCompat drawableCompat=VectorDrawableCompat.create(getResources(), R.drawable.layer_list_ic_user, tvUserName.getContext().getTheme());
tvUserName.setCompoundDrawablesRelativeWithIntrinsicBounds(drawableCompat, null, null, null);
II. Если TextView находится внутри фрагмента:
TextView tvUserName= (TextView )view.findViewById(R.id.et_username_or_email);
VectorDrawableCompat drawableCompat=VectorDrawableCompat.create(getActivity().getResources(), R.drawable.layer_list_ic_user, tvUserName.getContext().getTheme());
tvUserName.setCompoundDrawablesRelativeWithIntrinsicBounds(drawableCompat, null, null, null);
Для получения дополнительной информации о VectorDrawableCompat см. ссылку
Ответ 5
Android 5.0 (API уровня 21) и выше обеспечивает поддержку векторной поддержки. Если ваше приложение имеет минимальный уровень API, который ниже, Vector Asset Studio добавляет векторный файл для рисования в ваш проект; также, во время сборки Gradle создает растровые изображения PNG с различными разрешениями. Gradle генерирует плотности PNG, определенные свойством сгенерированных свойств домена (DSL), созданным в файле build.gradle. Для создания PNG для системы сборки требуется Android Plugin для Gradle 1.5.0 или новее.
Это неверно, если вы включили в свой gradle
vectorDrawables.useSupportLibrary = true
либо установите значение false, либо полностью удалите строку, и все ваши векторы будут работать так, как они были. Но для старых версий андроида они смогут полагаться на преобразованный PNG
Ответ 6
Я использую новую библиотеку поддержки, и все, что мне нужно сделать, это:
compile 'com.android.support:appcompat-v7:25.1.1'
В файле Build.gradle
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
Теперь, когда вы используете такой же фрагмент, активность или адаптер, используйте это как первую строку в своем классе
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
после этого используйте, как и раньше, something.xml
<ImageView
android:id="@+id/ivMainNavigationIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Something.java
thumbIcon.setImageDrawable(ContextCompat.getDrawable(context,R.drawable.ic_check_circle_black_24dp));
или если у вас есть требуемый идентификатор для динамического набора
thumbIcon.setImageDrawable(ContextCompat.getDrawable(context,drawableID));
Ответ 7
Форма android studio 3.0.0 android: src не поддерживает векторное изображение и ниже 21 мое исключение исключения. используйте приложение: srcCompat для векторного изображения. Храните файлы векторного изображения внутри папки drawable.
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
И в классе приложения определите это:
@Override
public void onCreate() {
super.onCreate();
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
Теперь вы можете использовать ваш .xml файл. Не забудьте указать эту ссылку: xmlns: app = "http://schemas.android.com/apk/res-auto"
<RelativeLayout
android:id="@+id/counterValuePanel"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_cart_notify"/>
</RelativeLayout>
Теперь вы можете использовать приложение: srcCompat = "@drawable/ic_cart_notify", но если вы попытаетесь использовать в android: background или android: drawableLeft, то у вас есть исключение "Ошибка раздувания". Для этого создайте новый обернутый файл .xml, ic_cart_notify - значок вектора.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_cart_notify"/>
</layer-list>