Android Selector Drawable с VectorDrawables srcCompat

У меня возникла проблема с новой обратной совместимостью с VectorDrawables. В библиотеке поддержки 23.2 была новая функция для обратной совместимости с Android VectorDrawables.

У меня есть ImageView, которому назначается SelectorDrawable. Этот Drawable содержит несколько VectorDrawables, поэтому я решил использовать приложение: srcCompat для совместимости. Но это не работает на моей Galaxy S2 с Android 4.1.2.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_gps_fixed_24dp"android:state_activated="true" android:state_selected="true"></item>
    <item android:drawable="@drawable/ic_gps_not_fixed_24dp" android:state_activated="true" android:state_selected="false"></item>
    <item android:drawable="@drawable/ic_gps_not_fixed_24dp" android:state_activated="false" android:state_selected="true"></item>
    <item android:drawable="@drawable/ic_gps_off_24dp" android:state_activated="false" android:state_selected="false"></item>
    <item android:drawable="@drawable/ic_gps_not_fixed_24dp"></item>
</selector>

Все чертежи являются векторными xml файлами.

При использовании этого SelectorDrawable с srcCompat я получаю эту ошибку:

  Caused by: android.content.res.Resources$NotFoundException: File res/drawable/  Caused by: android.content.res.Resources$NotFoundException: File res/drawable/ic_gps_fixed_24dp.xml from drawable resource ID #0x7f0201c1
                                                                           at android.content.res.Resources.loadDrawable(Resources.java:1951)
                                                                           at android.content.res.Resources.getDrawable(Resources.java:672)
                                                                           at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:173)
                                                                           at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:881).xml from drawable resource ID #0x7f0201c1

Использование android: src еще хуже.

Если я использую одну из векторных чертежей с приложением: srcCompat все работает нормально. Поэтому я думаю, что это проблема с SelectorDrawable и совместимостью.

У кого-то была такая же проблема и нашли решение, или в настоящее время невозможно использовать VectorDrawables в SelectorDrawables до Android 5?

Краткие факты:

  • Компилировать целевой API 23
  • Поддержка Libraray 23.3.0
  • vectorDrawables.useSupportLibrary = true
  • Gradle 2.0

Ответ 1

некоторые вещи изменились с тех пор, как я задал этот вопрос, поэтому сам отвечу.

С поддержкой библиотеки 23.4.0 поддержка VectorDrawables из Ressources была повторно установлена: Android Support Library 23.4.0 теперь доступно

Более подробную информацию об этом можно найти в этом приложении Google I/O 2016: Что нового в библиотеке поддержки - Google I/O 2016

Вам нужно добавить это к каждой операции, где вы хотите использовать VectorDrawables на устройствах под Android 5.0 (Codename Lollipop, уровень API 21):

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Итак, теперь вы можете использовать VectorDrawables в DrawableContainers, но он все равно может вызвать некоторые проблемы, упомянутые выше в источниках, поэтому используйте его с осторожностью.

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

Ответ 2

Как упоминал @Jahnold в комментарии к вопросу, поддержка загрузки вектора, переносимого из xml-списка xml state, была удалена в 23.3.

Однако я нашел несколько подходов, которые могут помочь.

1. Использование оттенка

Подход подходит, если чертежи из выбранного списка состояний отличаются только цветами.

Сначала создайте только один вектор, который можно рисовать с оттенком и белый fillColor:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tintMode="multiply"
    android:tint="@color/button_tint">

    <path
        android:fillColor="#ffffff"
        android:pathData="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>

    <path
        android:pathData="M0 0h24v24H0z"/>

</vector>

Во-вторых, создайте список состояний цвета button_tint.xml, расположенный в res/color

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#555555" android:state_enabled="false"/>
    <item android:color="#6699dd"/>
</selector>

Не забудьте добавить строки ниже в build.gradle или подход не будет работать на старых версиях Android.

defaultConfig {
    vectorDrawables.useSupportLibrary = true
}

2. Создание жесткого кода StateListDrawable

Подход подходит, если вы используете для векторных векторных элементов списка, которые отличаются не только цветом, но и фигурой, поэтому вам нужно создать несколько разных xml файлов. Затем вы можете создать StateListDrawable программно, как показано в .

Ответ 3

После просмотра Что нового в библиотеке поддержки - Google I/O 2016 Я заметил один полезный метод в классе AppCompatResources. Это AppCompatResources#getColorStateList(Context context, int resId). С помощью этого метода я реализовал селектор с векторными чертежами. Вот мой селектор цветов icon_selector:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/red_selected" android:state_selected="true"/>
    <item android:color="@color/red_pressed" android:state_pressed="true"/>
    <item android:color="@color/red"/>
</selector>

И есть java-метод, который возвращает тонированное drawable:

    private Drawable getTintedDrawable(@DrawableRes int drawableId) {
    Drawable drawable;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        drawable = getResources().getDrawable(drawableId, getTheme());
    } else {
        drawable = getResources().getDrawable(drawableId);
    }
    drawable = DrawableCompat.wrap(drawable);
    DrawableCompat.setTintList(drawable.mutate(), AppCompatResources.getColorStateList(this, R.color.selector_nav_bar_item_ico));
    return drawable;
   }

Вы можете использовать его, как показано ниже.

yourImageView.setImageDrawable(getTintedDrawable(R.drawable.ic_vector_image));