Использование векторной графики для Android при падении Lollipop

Я использую векторные рисунки в Android до Lollipop, и вот некоторые из моих библиотек и версий инструментов:

  • Android Studio: 2.0
  • Плагин Android Gradle: 2.0.0
  • Инструменты сборки: 23.0.2
  • Библиотека поддержки Android: 23.3.0

Я добавил это свойство на своем уровне приложения Build.Gradle

android {  
  defaultConfig {  
    vectorDrawables.useSupportLibrary = true  
   }  
}

Стоит также упомянуть, что я использую дополнительные элементы рисования, такие как LayerDrawable(layer_list), как указано в официальном блоге Android ( ссылка здесь), для настройки рисования для векторных рисунков за пределами app:srcCompat

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/search"/>
</level-list>

Вы найдете ссылки на векторные графические объекты вне приложения:srcCompat завершится с ошибкой до Lollipop. Однако AppCompat поддерживает загрузку векторных рисованных объектов, когда на них ссылаются в другом рисуемом контейнере, таком как StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable и RotateDrawable. Используя эту косвенную ссылку, вы можете использовать векторные объекты рисования в таких случаях, как атрибут android:drawableLeft в TextView, который обычно не может поддерживать векторные рисунки.

Когда я использую app:srcCompat все работает нормально, но когда я использую:

android:background
android:drawableLeft
android:drawableRight
android:drawableTop
android:drawableBottom

на ImageView, ImageButton, TextView или же EditText до Lollipop, он бросает ожидание:

Caused by: android.content.res.Resources$NotFoundException: File res/drawable/search_toggle.xml from drawable resource ID #0x7f0200a9

18 ответов

Решение

Я думаю, что это происходит, потому что Вектор поддержки был отключен в последней версии библиотеки: 23.3.0

Согласно этому посту:

Для пользователей AppCompat мы решили удалить функциональность, которая позволяет использовать векторные рисунки из ресурсов на устройствах, предшествующих Lollipop, из-за проблем, обнаруженных в реализации в версии 23.2.0 / 23.2.1 (ISSUE 205236). Использование app:srcCompat и setImageResource() продолжает работать.

Если вы посещаете выпуск ISSUE 205236, кажется, что они будут включены в будущем, но проблема с памятью не будет решена в ближайшее время:

В следующем выпуске я добавил opt-in API, где вы можете снова включить поддержку VectorDrawable, которая была удалена. Это идет с теми же предостережениями, что и раньше (использование памяти и проблемы с обновлением конфигурации).

У меня была похожая проблема. Таким образом, в моем случае я снова вернул все иконки, которые используют векторное рисование из ресурса, в изображения PNG (поскольку проблема с памятью будет происходить даже после того, как они предоставят возможность включить ее снова).

Я не уверен, что это лучший вариант, но, по моему мнению, он исправляет все сбои.

ОБНОВИТЬ

Они снова включили этот VectorDrawable в
Библиотека поддержки Android 23.4.0

Для пользователей AppCompat мы добавили opt-in API для повторного включения поддержки VectorDrawable s из ресурсов (поведение, описанное в 23.2) через AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) - имейте в виду, что это все еще может вызывать проблемы с использованием памяти и проблемы с обновлением экземпляров конфигурации, поэтому по умолчанию он отключен.

Может быть build.gradle настройка теперь устарела, и вам просто нужно включить ее в надлежащих действиях (однако, нужно проверить).

Теперь, чтобы включить его, вы должны сделать:

public class MainActivity extends AppCompatActivity {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

    ...
}

У меня такая же проблема. Но, занимаясь исследованиями и разработками, я получил ответ.

Для использования Imageview и ImageButton app:srcCompat="@drawable/...." и для других представлений, таких как Button, Textview, вместо использования drawableLeft/right..."в XML, программно задайте drawables как:

button.setCompoundDrawablesWithIntrinsicBounds(AppCompatResources.getDrawable(mContext,R.drawable.ic_share_brown_18dp), null, null, null);

И используйте "AppCompatResources", чтобы получить отрисовку.

Чтобы уточнить другие очень хорошие ответы, вот схема, которая может вам помочь. Это допустимо, если у вас есть библиотека поддержки с 23.4.0 по крайней мере 25.1.0.

VectorDrawable шпаргалка

Ответ от Guillherme P довольно удивительный. Просто для того, чтобы сделать небольшое улучшение, вам не нужно добавлять эту строку в каждое действие, если вы добавили ее один раз в класс Application, она также будет работать.

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

ПОМНИТЕ: Вам все еще нужно включить использование библиотеки поддержки в gradle:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Кроме того, убедитесь, что вы используете версию библиотеки поддержки больше, чем v23.4, когда Google вернул поддержку Drawable Containers для VectorDrawables ( примечание к выпуску)

Обновить

И для изменения кода:

  1. Не забудьте обновить до app:srcCompat каждое место, которое принимает android:src атрибут (IDE предупредит вас, если он недействителен, как для <bitmap> тег).
  2. За drawableLeft, drawableStart, drawableRight, drawableEnd атрибуты, используемые в TextView и аналогичные виды, вам придется установить их программно на данный момент. Пример настройки drawableStart:

    Drawable drawable = AppCompatResources.getDrawable(
            getContext(),
            R.drawable.your_vector_drawable);
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        textView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
    }
    

У меня такая же проблема. И исправить это, удалив

vectorDrawables.useSupportLibrary = true

Моя целевая версия 25 и поддержка библиотеки

 compile 'com.android.support:appcompat-v7:25.3.1'

VectorDrawables на pre-lollipop должен нормально работать без использования

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

Если вы хотите использовать VectorDrawables внутри ImageViews, вы можете использовать атрибут srcCompat и это будет работать, но внутри кнопок или TextViews это не будет, поэтому вам нужно обернуть Drawable в InsetDrawable или LayerDrawable. Я обнаружил еще одну хитрость: если вы используете привязку данных, вы можете сделать это:

android:drawableLeft="@{@drawable/vector_ic_access_time_24px}"
android:drawableStart="@{@drawable/vector_ic_access_time_24px}"

Это будет работать волшебным образом, я не исследовал, что происходит за кулисами, но я предполагаю, что TextView использует метод getDrawable из AppCompatResources или аналогичный.

Много НИОКР, наконец, получим это решение для сбоев на устройствах перед леденцом на палочке.

Для просмотра изображений

  • используйте приложение:srcCompat вместо android:src

Для TextView/EditText

  • Удалите drawableleft,drawableright.... и установите из нарисованного Java-кода.

txtview.setCompoundDrawablesWithIntrinsicBounds (AppCompatResources.getDrawable (EventDetailSinglePage.this, R.drawable.ic_done_black_24_n), null, null, null);

Для Build.gradle

vectorDrawables.useSupportLibrary = true

Самый простой способ использования:

  app:drawableRightCompat ="@drawable/ic_mobilelogin"
  app:drawableEndCompat="@drawable/ic_mobilelogin"
app:srcCompat="@drawable/ic_mobile"

и... просто используйте приложение:**Compat для совместимости

Также добавьте поддержку build.gradle (Модуль)

android {
 defaultConfig {
vectorDrawables.useSupportLibrary = true
               }
        }

Для тех, кто обновляет до Android Gradle 3.0 и выше, нет необходимости использовать AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)или установить vectorDrawables.useSupportLibrary = true (добавить это вызовет проблемы) и использовать app:srcCompatэто просто работает.

У меня уйдет два дня, чтобы понять это, и я не нашел ни одной связанной документации в документации Google...

We tried 3 things

vectorDrawables.useSupportLibrary = true

Setting setCompatVectorFromResourcesEnabled in Application class

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

And use app:srcCompat

But even after that it was failing with

Resources$NotFoundException: File res/drawable/$my_icon__0.xml from color state list resource ID #0x7f080008

then we figured out that our SVG had a Gradient tag. Converting the gradient tag to individual paths for below API <= 23 and using the same SVG API >= 24 worked.

Got help from this answer /questions/6375608/teggradient-vnutri-xml-vyizyivaet-sboj-android/6375609#6375609

После использования приведенного ниже кода.

android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true  
                }
        }




public class App extends Application {
static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}}

Тем не менее, проблема с векторными изображениями существует для следующих атрибутов:

DrawableEnd, DrawableStart, DrawableTop, DrawableBottom, Фон

В этом случае выполните следующие действия. Вместо того, чтобы ссылаться на векторное изображение напрямую, используйте тег селектора в качестве промежуточного файла для рисования.

Пример:

ic_warranty_icon.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="17"
android:viewportHeight="24">

<path
    android:fillColor="#fff"
    android:pathData="M10.927,15.589l-1.549,0.355a7.47,7.47 0,0 1,-0.878 0.056c-4.136,0 -7.5,-3.364 -7.5,-7.5s3.364,-7.5 7.5,-7.5 7.5,3.364 7.5,7.5c0,3.286 -2.126,6.078 -5.073,7.089zM8.5,2a6.508,6.508 0,0 0,-6.5 6.5c0,3.583 2.917,6.5 6.5,6.5s6.5,-2.917 6.5,-6.5 -2.917,-6.5 -6.5,-6.5z" />

safe_ic_warranty_icon.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_warranty_icon"  />
</selector>

Ваш TextView/Layout.

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawableStart="@drawable/ic_warranty_icon"
       />


<LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/ic_warranty_icon"
       />

Я использую VectorDrawables на устройствах Pre-lollipop, и вот как я это делаю:

Шаг 1: Поместите это в ваш уровень приложения.

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Шаг 2:

Поместите это в свой класс Application и не забудьте зарегистрировать свой класс Application в файле манифеста.

public class App extends Application {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
}

Шаг 3:

Получите VectorDrawables используя,

imageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.my_vector_drawable));

Я боролся с этим часами.

Я перепробовал все, о чем мне говорили эти ответы, но мое приложение не переставало давать сбой. Я удалил эту строку:app:srcCompat="@drawable/keyboard"и мое приложение перестало давать сбой. а затем, когда я добавил то же самое, он снова начал вылетать. Итак, я решил открыть этот файл и увидел ошибку в первой строке:

"Раскладываемая клавиатура" не имеет декларации в базовой папке с возможностью переноса; это может привести к сбоям.

Я щелкнул правой кнопкой мыши файл и выбрал "Показать в проводнике", и он был не в папке с возможностью рисования, а в каталоге drawable-v24. Поэтому я скопировал его и вставил в каталог с возможностью рисования и, наконец, избавился от сбоев.

In my case, I was using a TabLayout, which I configured as it :

      TabLayoutMediator(tabLayout!!, viewPager!!) { tab, position ->
    if (position == 0)
        tab.icon = ResourcesCompat.getDrawable(resources, R.drawable.ic_list, theme)
    else
        tab.icon = ResourcesCompat.getDrawable(resources, R.drawable.ic_building_map, theme)
}.attach()

The app was crashing at line tab.icon = ...

I change these to tab.setIcon(R.drawable.my_vector_asset), as it :

      TabLayoutMediator(tabLayout!!, viewPager!!) { tab, position ->
    if (position == 0)
        tab.setIcon(R.drawable.ic_list)
    else
        tab.setIcon(R.drawable.ic_building_map)
}.attach()

And it worked !

Просто наложите вектор, отображаемый в список состояний, и проблема будет решена.

Например, у вас есть стрелка назад векторное изображение:

ic_back_arrow.xml

да, вы должны наложить его на список слоев xml (ic_back_arrow_vector_vector.xml):

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_back_arrow"/>
</layer-list>

Потому что логика:

vectorDrawables.useSupportLibrary = true

а также

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

не поможет вам на некоторых китайских устройствах и старых устройствах Samsung. Если вы не перекрываете их, это не удастся.

Предложение Гильерме Р не сработало для меня. Я пошел дальше и принял решение использовать png там, где мне нужно делать что-то вне приложения: srcCompat, т.е. drawableLeft, drawableRight и т. Д. Это было довольно легко изменить, и у него нет потенциальных проблем с памятью AppCompatDelegate.setCompatVectorFromResourcesEnabled(правда); вводит.

Теперь есть более простое решение, просто используйте app:drawableRightCompat из пространства имен приложения.

Или в стиле:

<style name="YourStyle">
    <item name="drawableRightCompat">@drawable/your_vector</item>
</style>

Альтернативой ответу Бенни является создание Activity суперкласс:

public abstract class VectorDrawableActivity extends AppCompatActivity {
  static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
  }

  //...
}

Теперь продлим VectorDrawableActivity вместо AppCompatActivity,

Другие вопросы по тегам