Подтвердить что ты не робот

Векторный 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 они вызывают хаос. Есть ли способы обхода?

4b9b3361

Ответ 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. Если вы обновляете конфигурацию вручную, тогда вы, вероятно, не хотите чтобы включить это. Вы были предупреждены.