Использование векторных чертежей Android при сбое Lollipop до сбоя


95

Я использую векторные чертежи в 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. Используя это косвенное обращение, вы можете использовать векторные чертежи в таких случаях, как атрибут TextView android: drawableLeft, который обычно не поддерживает векторные чертежи.

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

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

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

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


Чтобы увидеть, как использовать VectorDrawable с drawableLeft, drawableRight, drawableTop, drawableBottom, ознакомьтесь с этим ответом
Бехзад Бахманьяр,

Вы можете проверить мой ответ здесь? stackoverflow.com/a/40523623/2557258
Yazon2006

В моем случае чертежи vactor не были в правильном пакете (открытое представление проекта), исходный ответ здесь stackoverflow.com/a/35836318/2163045
murt

Ответы:


104

ПОСЛЕДНЕЕ ОБНОВЛЕНИЕ - июнь / 2019

Библиотека поддержки немного изменилась с момента первоначального ответа. Теперь даже плагин Android для Gradle может автоматически генерировать PNG во время сборки. Итак, ниже представлены два новых подхода, которые должны работать в наши дни. Вы можете найти больше информации здесь:

Поколение PNG

Gradle может автоматически создавать изображения PNG из ваших ресурсов во время сборки. Однако при таком подходе поддерживаются не все элементы xml . Это решение удобно, потому что вам не нужно ничего менять в коде или в build.gradle. Просто убедитесь, что вы используете Android Plugin 1.5.0 или выше и Android Studio 2.2 или выше .

Я использую это решение в своем приложении и отлично работает. Дополнительный флаг build.gradle не требуется. Никаких взломов не требуется. Если вы перейдете в / build / generated / res / pngs / ..., вы увидите все сгенерированные PNG.

Итак, если у вас есть простой значок (поскольку поддерживаются не все элементы xml), это решение может сработать для вас. Просто обновите Android Studio и плагин Android для Gradle.

Библиотека поддержки

Возможно, это решение, которое подойдет вам. Если вы пришли сюда, это означает, что ваша Android Studio не генерирует PNG автоматически. Итак, ваше приложение дает сбой.

Или, может быть, вы вообще не хотите, чтобы Android Studio генерировала PNG.

В отличие от этого «автоматического создания PNG», которое поддерживает подмножество элементов XML, это решение поддерживает все теги xml. Итак, у вас есть полная поддержка вашего векторного рисования.

Вы должны сначала обновить свой build.gradle, чтобы поддерживать его:

android {
  defaultConfig {
    // This flag will also prevents Android Studio from generating PNGs automatically
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
  // Use this for Support Library
  implementation 'com.android.support:appcompat-v7:23.2.0' // OR HIGHER

  // Use this for AndroidX
  implementation 'androidx.appcompat:appcompat:1.1.0' // OR HIGHER
}

А затем используйте app:srcCompatвместо android:srcпри загрузке VectorDrawables. Не забывай об этом.

Для TextView, если вы используете androidxверсию библиотеки поддержки, вы можете использовать app:drawableLeftCompat(или справа, сверху, снизу) вместоapp:drawableLeft

В случае CheckBox/ RadioButtonиспользуйте app:buttonCompatвместо android:button.

Если вы не используете androidxверсию библиотеки поддержки и вашminSdkVersion она 17или выше, или вы используете кнопку, вы можете попытаться установить программно через

Drawable icon = AppCompatResources.getDrawable(context, <drawable_id>);
textView.setCompoundDrawablesWithIntrinsicBounds(<leftIcon>,<topIcon>,<rightIcon>,<bottomIcon>);

ОБНОВЛЕНИЕ - июль / 2016

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

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

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

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

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

    ...
}

Оригинальный ответ - апрель 2016 г.

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

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

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

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

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

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

Не уверен, что это лучший вариант, но, на мой взгляд, он исправляет все сбои.


1
Спасибо @Guilherme P., но почему вы не удалили vectorDrawables.useSupportLibrary = trueperoperty, чтобы снова включить создание файлов png во время сборки ?
Бехзад Бахманьяр,

1
Это было отключено в последней версии v23.3.0 из-за проблем с памятью. Таким образом, они не могут генерировать png во время выполнения ... Вот почему в ошибке logcat они печатают: неизвестный вектор тега (или что-то в этом роде).
W0rmH0le

4
Вот инструкции по включению plus.google.com/+AndroidDevelopers/posts/B7QhFkWZ6YX . К сожалению, VectorDrawables все еще не работает на устройстве Pre-Lollipop. Я использую библиотеку поддержки 23.4.0, и в defaultConfig {} вызываются как «generatedDensities = []», так и «vectorDrawables.useSupportLibrary = true».
Адам Гурвиц

1
@AdamHurwitz Я обновил ответ .. Кажется, он снова был включен .. Однако теперь вы должны включить его по-другому.
W0rmH0le

1
@juztcode Вы правы. Вы должны использовать androidx.appcompat: appcompat: 1.1.0
W0rmH0le

63

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

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

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

И используйте «AppCompatResources», чтобы получить возможность рисования.


60

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

VectorDrawable шпаргалка


1
если вы пытаетесь установить drawableLeft, оберните его внутри drawable, как указано здесь. medium.com/@chrisbanes/...
nizam.sp

Спасибо, что эта таблица нам очень помогает.
silntsudo 07

39

Ответ от 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);
    }
    

помните, что вам нужно включить использование библиотеки поддержки для векторных чертежей в gradle: vectorDrawables.useSupportLibrary = true
Benny

2
Ага. Я знаю. Но необходима оболочка, чтобы векторные чертежи работали как чертежи для TexView, поэтому этот ответ неполный.
cesards

1
Отличный ответ. Это особенно хорошо для приложений, все действия которых расширены из настраиваемой базовой активности.
Гонконг

14

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

vectorDrawables.useSupportLibrary = true

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

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

1
это сработало для меня. Спасибо. Я только что удалил этоvectorDrawables.useSupportLibrary = true
Android Mediocre

Я думаю, что это неправильный способ сделать это, в любом случае я проголосовал за ваш ответ !!
Harish Reddy

Спасибо. t работает для моего приложения. Все векторные чертежи по-прежнему работают, если они были удалены. Приложение использует com.android.support:appcompat-v7:28.0.0
Гонконг,

10

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 или аналогичный.


Как установить векторное изображение в селекторе?
Тушар Гогна

после установки vectorDrawables.useSupportLibrary = true в Gradle по умолчанию и AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); в действии при создании Чтобы избежать сбоя с android: drawableleft в Textview , установите drawble left для текстового просмотра программно, например: textview.setCompoundDrawablesWithIntrinsicBounds (R.drawable.movie, 0, 0, 0);
Афджалур Рахман Рана

7

Много исследований и разработок, наконец, получение этого решения для сбоев на устройствах, предшествующих леденцу.

Для Imageview

  • используйте app: 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


1
Это было уникальное решение, которое работало с TextInputEditText.
heronsanches

1
Ужасно, моя проблема решена. Это приемлемый ответ.
DJtiwari

7

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

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

и ... просто используйте app:**Compatдля совместимости. Также добавьте поддержку build.gradle(модуль)

android {
   defaultConfig {
       vectorDrawables.useSupportLibrary = true
   }
}

app: drawableEndCompat и app: drawableRightCompat в значительной степени то же самое, если его английский
Хоссам Хассан

5

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

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


Интересно, что я использую gradle 3.3.0, и это решение работает. Однако Android Studio все еще говорит мне включить set vectorDrawables.useSupportLibrary = true.
masterwok

2

Я использую 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));

2

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

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"
       />

Благодарность !!! Для свойства background добавление селектора между ними вместо прямого использования vector drawable сработало для pre-lollipop api (19).
Ankur

в моем случае это по-прежнему не работает для API (16), даже с selector
упаковкой

1

Мы попробовали 3 вещи

vectorDrawables.useSupportLibrary = true

Установка setCompatVectorFromResourcesEnabled в классе Application

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

И использовать app:srcCompat

Но даже после этого он не работал с

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

затем мы выяснили, что у нашего SVG есть тег Gradient. Преобразование тега градиента в отдельные пути для API <= 23 ниже и с использованием того же SVG API> = 24 работало.

Получил помощь от этого ответа https://stackoverflow.com/a/47783962/2171513


Я не знаю, почему никто не проголосовал за это, но на самом деле это могло быть решением моей проблемы. Спасибо
DevMike01

1

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

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

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

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


0

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

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

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. Если не перекрыть их, ничего не получится.


-2

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


-3

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

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

  //...
}

Теперь расширение VectorDrawableActivityвместо AppCompatActivity.


@cesards Почему бы и нет?
Code-Apprentice
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.