web-dev-qa-db-fra.com

Android Sélecteur pouvant être dessiné avec VectorDrawables srcCompat

Je suis confronté à un problème de compatibilité ascendante avec VectorDrawables. Dans la bibliothèque de support technique 23.2, une nouvelle fonctionnalité de compatibilité ascendante avec Android VectorDrawables a été introduite.

J'ai un ImageView qui est un SelectorDrawable assigné à. Ce Drawable contient plusieurs VectorDrawables, alors j’ai pensé que je devrais utiliser app: srcCompat pour la compatibilité. Mais cela ne fonctionne pas sur mon Galaxy S2 avec 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>

Tous les dessins sont des fichiers vectoriels xml.

Lorsque j'utilise ce SelectorDrawable avec srcCompat, j'obtiens cette erreur:

  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

en utilisant Android: src est encore pire.

Si j'utilise l'un des vecteurs dessrables avec app: srcCompat, tout fonctionne correctement. Donc, je suppose que c'est un problème avec le SelectorDrawable et la compatibilité.

Quelqu'un a-t-il eu le même problème et a-t-il trouvé une solution ou n'est-il pas possible d'utiliser VectorDrawables dans SelectorDrawables avant Android 5?

Les faits en bref:

  • API de compilation cible 23
  • Support Libraray 23.3.0
  • vectorDrawables.useSupportLibrary = true
  • Gradle 2.0
59
marilion91

certaines choses ont changé depuis que j'ai posé cette question, je vais donc y répondre moi-même.

Avec Support Library 23.4.0, la prise en charge de VectorDrawables à partir de Ressources a été réactivée: Android Support Library 23.4.0 disponible maintenant

Vous trouverez plus d'informations à ce sujet dans cette distribution de Google I/O 2016: Nouveautés de la bibliothèque de support - Google I/O 2016

Vous devez l'ajouter à toutes les activités pour lesquelles vous souhaitez utiliser VectorDrawables sur les périphériques suivants: Android 5.0 (nom de code Lollipop, API niveau 21):

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Vous pouvez donc maintenant utiliser VectorDrawables dans DrawableContainers, mais cela peut toujours causer certains problèmes, comme mentionné dans les sources ci-dessus. Utilisez-le donc avec prudence.

Jusqu'à présent, je n'avais pas réactivé cette fonctionnalité dans mon application, mais je changerai beaucoup d'icônes en VectorDrawables lors de ma prochaine version majeure et approfondirai ce sujet.

64
marilion91

Comme @Jahnold l'a mentionné dans le commentaire à la question, la prise en charge du chargement du vecteur pouvant être dessiné à partir d'une liste xml state a été supprimée dans 23.3.

Cependant, j'ai trouvé plusieurs approches qui peuvent aider.

1. Utilisation de la teinte

L’approche est appropriée si les éléments dessinables de l’état sélectionné ne diffèrent que par couleurs.

Tout d’abord, créez un seul vecteur dessinable en blanc et en nuance 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>

Deuxièmement, créer une liste d'état de couleurs button_tint.xml placé dans 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>

N'oubliez pas d'ajouter les lignes suivantes à build.gradle ou l’approche ne fonctionnera pas sur les anciennes versions Android.

defaultConfig {
    vectorDrawables.useSupportLibrary = true
}

2. Hardcode créant StateListDrawable

L’approche est appropriée si vous utilisez pour le vecteur liste d’états pouvant être dessiné une différence non seulement par une couleur mais aussi par un chiffre; vous devez donc créer plusieurs fichiers xml différents. Ensuite, vous pouvez créer StateListDrawable par programme, comme indiqué dans un réponse .

53
Sergei Vasilenko

Après avoir regardé Nouveautés de la bibliothèque de support technique - Google I/O 2016, j'ai remarqué une méthode utile dans la classe AppCompatResources. C'est AppCompatResources#getColorStateList(Context context, int resId). Avec l'aide de cette méthode, j'ai implémenté selector with drawables vector. Voici mon fichier de sélecteur de couleur 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>

Et il existe une méthode Java qui renvoie les éléments colorables:

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;
}

Vous pouvez l'utiliser comme indiqué ci-dessous

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

Fonctionne bien avec les changements ci-dessous.

static {
 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Ajouté dans la classe d'application.
app build.gradle dans defaultConfig

vectorDrawables.useSupportLibrary = true
2
Raja Peela