web-dev-qa-db-fra.com

Comment utiliser les dessins vectoriels avec View en plus d'ImageView avec srcCompat?

app:srcCompat avec ImageView permet une utilisation rétrocompatible des dessins vectoriels. Mais comment pouvez-vous les utiliser avec d'autres Views en plus de ImageView? Par exemple, les attributs TextView tels que Android:drawableLeft.

L'utilisation du vecteur drawable en tant que Android:icon avec MenuItem a également provoqué un crash avec l'exception suivante:

Fatal Exception: Android.view.InflateException: Binary XML file line #2: Error inflating class <unknown>
   at Android.view.LayoutInflater.createView(LayoutInflater.Java:626)
   at Android.view.LayoutInflater.createViewFromTag(LayoutInflater.Java:702)
   at Android.view.LayoutInflater.inflate(LayoutInflater.Java:470)
   at Android.view.LayoutInflater.inflate(LayoutInflater.Java:398)
   at Android.support.v7.view.menu.MenuItemImpl.setActionView(MenuItemImpl.Java:621)
   at Android.support.v7.view.menu.MenuItemImpl.setActionView(MenuItemImpl.Java:40)
   at Android.support.v4.view.MenuItemCompat.setActionView(MenuItemCompat.Java:310)
   at Android.support.v7.view.SupportMenuInflater$MenuState.setItem(SupportMenuInflater.Java:465)
   at Android.support.v7.view.SupportMenuInflater$MenuState.addItem(SupportMenuInflater.Java:479)
   at Android.support.v7.view.SupportMenuInflater.parseMenu(SupportMenuInflater.Java:196)
   at Android.support.v7.view.SupportMenuInflater.inflate(SupportMenuInflater.Java:118)
   at com.example.niceapp.context.main.MainActivity.onCreateOptionsMenu(MainActivity.Java:101)
   at Android.app.Activity.onCreatePanelMenu(Activity.Java:2578)

Avec Support Library 23.2.0, comment résoudre ce problème?

38
razzledazzle

Pour AppCompat version 23.3.0 où aucune solution de travail via le sélecteur XML (la réponse acceptée de razzledazzle), nous pouvons le faire par programme:

activity_main.xml

<Android.support.v7.widget.AppCompatImageButton
    Android:id="@+id/btnEnter"
    />

MainActivity.Java

AppCompatImageButton image = (AppCompatImageButton) findViewById(R.id.btnEnter);
if (image != null) {
    VectorDrawableCompat vcAccept = VectorDrawableCompat.create(getResources(), R.drawable.vc_accept, getTheme());
    VectorDrawableCompat vcAcceptWhite = VectorDrawableCompat.create(getResources(), R.drawable.vc_accept_white, getTheme());

    StateListDrawable stateList = new StateListDrawable();
    stateList.addState(new int[]{Android.R.attr.state_focused, -Android.R.attr.state_pressed}, vcAccept);
    stateList.addState(new int[]{Android.R.attr.state_focused, Android.R.attr.state_pressed}, vcAcceptWhite);
    stateList.addState(new int[]{-Android.R.attr.state_focused, Android.R.attr.state_pressed}, vcAcceptWhite);
    stateList.addState(new int[]{}, vcAccept);

    image.setImageDrawable(stateList);
}

Ce code est équivalent pour ce sélecteur xml:

<selector xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item Android:state_focused="true" Android:state_pressed="false" Android:drawable="@drawable/vc_accept" />
    <item Android:state_focused="true" Android:state_pressed="true" Android:drawable="@drawable/vc_accept_white" />
    <item Android:state_focused="false" Android:state_pressed="true" Android:drawable="@drawable/vc_accept_white" />
    <item Android:drawable="@drawable/vc_accept" />
</selector>

METTRE À JOUR

Si le vecteur drawable n'est pas affiché à l'aide de l'API 23, vous devez d'abord convertir la variable VectorDrawable en une variable Drawable régulière. Si vous voulez utiliser setCompoundDrawablesWithIntrinsicBounds, vous devrez le faire, mais pour StateListDrawable, je n'avais pas besoin de le faire.

Drawable icon;
if (Android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
    icon = VectorDrawableCompat.create(getResources(), R.drawable.vc_icon, getContext().getTheme());
} else {
    icon = getResources().getDrawable(R.drawable.vc_icon, getContext().getTheme());
}
29
Petr Daňa

Update 2: ils ont ajouté une option pour l'activer à nouveau dans Support Library 23.4.0:

Pour les utilisateurs d’AppCompat, nous avons ajouté une API d’inscription permettant de réactiver le support Vector Drawables à partir de ressources (comportement décrit dans 23.2) via AppCompatDelegate.setCompatVectorFromResourcesEnabled () - gardez à l’esprit que cela peut toujours causer problèmes d'utilisation de la mémoire et problèmes de mise à jour des instances de configuration, d'où leur désactivation par défaut.

Update: Cela ne fonctionne plus à partir de la version 23.3.0

Pour les utilisateurs d’AppCompat, nous avons décidé de supprimer la fonctionnalité qui vous permettent d'utiliser des vecteurs drawables à partir de ressources sur des périphériques antérieurs à Lollipop en raison de problèmes rencontrés dans la mise en œuvre de la version 23.2.0/23.2.1 [ https://code.google.com/p/Android/issues/detail?id=205236 } _, https://code.google.com/p/Android/issues/detail? id = 204708] . En utilisant app: srcCompat et setImageResource () continue de fonctionner.

De _ { développeur Android Google+ post } _


Utiliser AppCompat et app: srcCompat est la méthode la plus infaillible pour intégrer des vecteurs dessinables à des vecteurs dans votre application.

Cette citation provient de la version officielle de blogpost pour la publication de la version 23.2.0 de la bibliothèque de prise en charge.

Le poste mentionne également les éléments suivants:

Vous constaterez que les vecteurs pouvant être directement référencés en dehors de app:srcCompat échoueront avant Lollipop. Cependant, AppCompat prend en charge le chargement des vecteurs dessinables de vecteurs lorsqu'ils sont référencés dans un autre conteneur dessinable tel que StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable et RotateDrawable. En utilisant cette indirection, vous pouvez utiliser des vecteurs dessrables vectoriels dans des cas tels que l’attribut TextView ’s Android:drawableLeft, qui ne serait normalement pas en mesure de prendre en charge les vecteurs drawables.

Cela se traduit par les étapes ci-dessous:

Étape 1:

Créez ou importez une ressource vectorielle dont vous avez besoin pour l'application. Par exemple, on peut créer un vecteur pouvant être dessiné pour l’icône de recherche et le nommer ic_action_search_vector.xml

Étape 2:

Créez une autre ressource pouvant être dessinée par proxy pour le vecteur dessiné précédemment créé. Supposons que, pour le ic_action_search_vector.xml précédent, ic_action_search.xml puisse être créé comme une simple StateListDrawable pouvant contenir les lignes ci-dessous:

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

Cette étape peut être ignorée si vous avez référencé le vecteur pouvant être dessiné à partir d'une autre ressource que vous utiliserez et que vous utiliserez avec votre vue.

Étape 3:

Utilisez la ressource drawable (ici, ic_action_search.xml) qui fait référence au vecteur drawable (ic_action_search_vector.xml) au lieu du vecteur directement dessinable. Pour un menu, cela ressemblerait à:

<item Android:id="@+id/search"
        Android:title="@string/search"
        Android:icon="@drawable/ic_action_search"
        app:showAsAction="always"/>

C'est la solution à ce problème!

45
razzledazzle

Vector drawables peut être utilisé avant Lollipop ailleurs que app:srcCompat, mais son prix est raisonnable.

J'ai créé ce diagramme pour aider (valable pour Support Library 23.4.0 à - au moins - 25.1.0).

 VectorDrawable cheatsheet

15
David Ferrand

Vous pouvez ajouter un vecteur pouvant être dessiné dans TextView par programme. Utilisez VectorDrawableCompat pour ajouter drawableLeft/drawableRight/drawableTop/drawableBottom/drawableStart/drawableEnd.

Pas:

je. Si TextView est à l'intérieur de l'activité: 

TextView tvUserName= (TextView)findViewById(R.id.et_username_or_email);
VectorDrawableCompat drawableCompat=VectorDrawableCompat.create(getResources(), R.drawable.layer_list_ic_user, tvUserName.getContext().getTheme());
tvUserName.setCompoundDrawablesRelativeWithIntrinsicBounds(drawableCompat, null, null, null);

ii. Si TextView est à l'intérieur de Fragment:

TextView tvUserName= (TextView )view.findViewById(R.id.et_username_or_email);
VectorDrawableCompat drawableCompat=VectorDrawableCompat.create(getActivity().getResources(), R.drawable.layer_list_ic_user, tvUserName.getContext().getTheme());
tvUserName.setCompoundDrawablesRelativeWithIntrinsicBounds(drawableCompat, null, null, null);

Pour plus d'informations sur VectorDrawableCompat Référez-vous ceci lien _

6
Arshak

Android 5.0 (API de niveau 21) et supérieur fournit un support pouvant être dessiné par vecteur. Si votre application a un niveau d'API minimum inférieur, Vector Asset Studio ajoute le fichier pouvant être dessiné par vecteur à votre projet. De plus, au moment de la construction, Gradle crée des images raster PNG à différentes résolutions. Gradle génère les densités PNG spécifiées par la propriété générée DSD (Domain Specific Language) dans un fichier build.gradle. Pour générer des fichiers PNG, le système de génération nécessite Android Plugin for Gradle 1.5.0 ou version ultérieure.

Ce n'est pas vrai si vous incluez dans votre note vectorDrawables.useSupportLibrary = true

soit mis à false, soit supprimez complètement la ligne et tous vos vecteurs fonctionneront comme ils étaient. Mais pour les anciennes versions d'Android, ils pourront compter sur le PNG converti.

1
Thunderstick

définir le vecteur drawable à côté drawable dans TextView sous Android

AppCompatTextViewnow supporte app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompat et app:drawableEndCompat composés tirables, prenant en charge les types pouvant être attirés rétroportés tels que VectorDrawableCompat.

Inclure ceci dans votre dossier

implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'

Dans votre vue texte, vous pouvez utiliser

app:drawableLeftCompat
app:drawableStartCompat
0
Darish

Formulaire Android studio 3.0.0 Android: src n’est pas compatible avec les images vectorielles et inférieur à 21 pour l’exception d’obtention. utilisez app: srcCompat pour une image vectorielle. Conservez tous les fichiers d’image vectorielle dans le dossier drawable .

Android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
    }  
 }

Et dans la classe d'application, définissez ceci:

@Override
public void onCreate() {
    super.onCreate();
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Vous pouvez maintenant utiliser votre fichier .xml. N'oubliez pas d'utiliser ce lien: xmlns: app = "http://schemas.Android.com/apk/res-auto"

<RelativeLayout
    Android:id="@+id/counterValuePanel"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" >
    <ImageView
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        app:srcCompat="@drawable/ic_cart_notify"/>
</RelativeLayout>

Maintenant, vous pouvez utiliser app: srcCompat = "@ drawable/ic_cart_notify" mais si vous essayez d'utiliser Android: background ou Android: drawableLeft, vous obtenez une exception "Erreur lors de l'inflation". Pour cela, créez un nouveau fichier .xml enroulable, ic_cart_notify est une icône vectorielle. 

<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item Android:drawable="@drawable/ic_cart_notify"/>
</layer-list>
0
Md Imran Choudhury

Dadou a raison. Donc, si vous souhaitez utiliser le sélecteur pour afficher avec VectorDrawables, vous devez ajouter: 

    static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(trfor);
}

à chaque activité pour laquelle vous souhaitez utiliser VectorDrawables sur des appareils dotés de versions inférieures à Android 5.

0
Djek-grif