Векторный Drawable в списке слоев на более старых версиях Android
В новых версиях Android следующий код:
<?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>
производит это безупречно.
Однако более ранние версии Android (API 16 и 19, из того, что я тестировал) вообще не нравятся, и я получаю
E/AndroidRuntime: FATAL EXCEPTION: main
Process: package.app, PID: 11490
android.view.InflateException: Binary XML file line #26: Error inflating class ImageView
при инфляции. Я использовал app:srcCompat
для всех моих ImageViews, поэтому проблем там нет.
Стандартные векторные чертежи также отлично работают, но при размещении в layer-list
они вызывают хаос. Есть ли способы обхода?
Ответы
Ответ 1
Атрибуты width/height для вектора, который можно вынести в вашем списке слоев, поддерживаются только в API 23 (Marshmallow) и выше. Если вы посмотрите на свой список слоев, который можно извлечь в редакторе Android Studio, эти атрибуты должны иметь желтые блоки вокруг них, а также предупреждение о том, что это не будет надежно работать на старых устройствах.
Но я думаю, вы можете избавиться от предупреждения и добиться такого же центрирующего эффекта, как это:
<?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>
Я тестировал это на старом телефоне API 15, и он работал нормально. Надеюсь, это сработает и для вас.
Обновление:
В предыдущей версии этого ответа я не рекомендовал использовать vectorDrawables.useSupportLibrary = true
со списками слоев, потому что это вызвало сбой. Тем не менее, я недавно узнал об обходном пути, который, как представляется, устраняет крах (избегая при этом файлов с автогенерируемыми файлами, которые @android разработчик). Вот краткое описание того, что нужно сделать для правильной работы:
Обязательно используйте srcCompat в вашем xml.
<android.support.v7.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/layer_list_with_svg" />
Добавить 'vectorDrawables.useSupportLibrary' в app/build.gradle
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
Добавить 'setCompatVectorFromResourcesEnabled (true)' to onCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
setContentView(R.layout.activity_main);
}
Почему все это необходимо?
Как объяснил мне более узнаваемый человек, это связано с тем, как Android загружает векторные переносы совместимости. Если вы используете vectorDrawables.useSupportLibrary = true
, то при использовании app:srcCompat
изображения будут загружать рисунки VectorDrawableCompat
. Когда ваш список слоев доступен, он не может понять, как создать эти ссылочные векторные ссылки. Но если вы включите setCompatVectorFromResourcesEnabled
, он попытается привязать векторную загружаемую загрузку на гораздо более низком уровне, чем изображения, и их атрибут app:srcCompat
, чтобы затем определить, как загрузить векторные чертежи, на которые ссылается слой список.
Ответ 2
Этот ответ опирается на статью AppCompat - возраст векторов Криса Банеса (который работает в Библиотеке поддержки). Для этого вопроса мы смотрим конкретно на раздел под названием "Волшебный" способ.
Авария, с которой вы столкнулись, связана с тем, что библиотека поддержки позволяет использовать некоторые способы использования VectorDrawables по умолчанию, а список слоев не является одним из них.
Существует специальный блок кода, который вы можете добавить в начало своей деятельности, чтобы включить другой VectorDrawable
, например <layer-list>
:
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
Примечание. связанная статья содержит опечатку в этом имени метода, используя "FromSources", это должно быть "FromResources", как показано выше.
Вам нужно будет добавить это к каждой Деятельности, где вы хотите использовать такие чертежи, или, возможно, включить ее в класс BaseActivity, из которого ваши другие действия распространяются.
В этой статье это должно означать следующее:
DrawableContainers, которые ссылаются на другие ресурсы drawables, которые содержат только векторный ресурс.
... StateListDrawable... InsetDrawable, LayerDrawable, LevelListDrawable и RotateDrawable.
Следует отметить, что этот метод сильно сочетается со словом "may", это может работать, и оно не включено по умолчанию, поэтому имейте в виду и убедитесь, что он действительно работает для вас!
Теперь есть еще одно измерение этого вопроса, кредит другим пользователям Selim Ajimi и Rapunzel Van Winkle для решения этой проблемы в своих ответах. <layer-list>
имеет другое поведение между API, в частности атрибуты width
и height
вашего <item>
, поддерживаемые только в API 23+. Это не является причиной вашего сбоя, и это не приведет к сбою вашего приложения, но будет означать, что ваш образ не будет выглядеть так, как только вы его используете в более ранних API.
Предложение от Rapunzel Van Winkle действительно кажется хорошим способом правильно позиционировать правильно API API (проверено на API 16 и 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>
Ответ 3
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="@[package:]drawable/drawable_resource"
android:id="@[+][package:]id/resource_name"
android:top="dimension"
android:right="dimension"
android:bottom="dimension"
android:left="dimension" />
</layer-list>
Как вы можете видеть здесь не имеет атрибутов width/height...
Вы можете добавить битмап к элементу Я думаю, что это лучшее решение
Ответ 4
Поддержка VectorDrawble на старых версиях Android довольно ограниченная, если вы используете vectorDrawables.useSupportLibrary = true
:
Вы можете использовать VectorDrawableCompat для API уровня 7 и AnimatedVectorDrawableCompat на всех устройствах под управлением Android 5.0 (API уровень 11) и выше. Как Android загружает чертежи, а не во все места который принимает идентификатор с возможностью рисования, например, в файле XML, поддерживает загрузку векторные образы. Пакет android.support.v7.appcompat добавил количество функций, облегчающих использование векторных чертежей. В первую очередь, когда вы используете пакет android.support.v7.appcompat с ImageView или с подклассами, такими как ImageButton и FloatingActionButton, вы можете используйте новое приложение: атрибут srcCompat для ссылочных векторных чертежей как а также любые другие доступные для Android возможности: src
Даже в коде вы ограничены:
Чтобы изменить чертежи во время выполнения, вы можете использовать setImageResource() как и раньше. Использование AppCompat и приложения: srcCompat является наиболее надежный метод интеграции векторных чертежей в ваше приложение.
Что вы можете сделать?
Несколько возможных решений:
-
имеют альтернативный вариант для VectorDrawable, который вы используете в LayerDrawable. Поместите его в res/drawable-xxhdpi, например, и VectorDrawable в res/drawable-anydpi.
-
не используйте vectorDrawables.useSupportLibrary = true
, пока у вас нет приложения minSdk, способного использовать VectorDrawable. Это будет работать, потому что IDE будет генерировать PNG файлы для вас.
-
программно создайте layerList (пример здесь), и для того, чтобы поместить VectorDrawable, используйте AppCompatResources.getDrawable
. Вы также можете сделать это с помощью XML, за исключением части размещения VectorDrawable.
Кстати, причина, по которой это ограничение, заключается в том, что Google не смог сделать ее эффективной и без проблем. Вы можете получить первоначальную попытку получить полную поддержку, используя AppCompatDelegate.setCompatVectorFromResourcesEnabled(true), но, как говорят документы, вы берете риск здесь:
Эта функция по умолчанию отключена, поскольку включение ее может вызвать проблемы с использованием памяти и проблемами с обновлением экземпляров Configuration. Если вы обновляете конфигурацию вручную, тогда вы, вероятно, не хотите чтобы включить это. Вы были предупреждены.