Est-il possible d'utiliser VectorDrawable dans Buttons et TextViews en utilisant Android: DrawableRight?

120

Lorsque j'utilise des ressources VectorDrawable dans une vue de texte ou une vue d'image, j'obtiens un crash d'exécution lors de l'utilisation de "android: DrawableRight" / "android: DrawableEnd" / "android: DrawableStart" / "android: DrawableLeft".

L'application se compilera correctement sans aucun avertissement.

j'utilise

  • Gradle 1.5
  • Bibliothèque de support 23.2 ('com.android.support:appcompat-v7:23.2.0')

Ce que j'ai trouvé, c'est que je peux attribuer des SVG par programme en Java sans plantages comme celui-ci.

TextView tv = (TextView) findViewById(R.id.textView);
tv.setCompoundDrawablesWithIntrinsicBounds(null,null, getResources().getDrawable(R.drawable.ic_accessible_white_36px),null);

(Je soupçonne qu'il s'agit d'un bogue de la bibliothèque de support pour 23.2.)

Mais est-il possible d'utiliser drawableRight, etc. pour les actifs SVG?

Voici ma mise en page

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="au.com.angryitguy.testsvg.MainActivity">


<TextView
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawableRight="@drawable/ic_accessible_white_36px"
    android:background="@color/colorPrimary"
    android:textColor="#FFFFFF"
    android:textSize="22sp"
    android:text="Hello World!"/>
</RelativeLayout>

Voici mon activité

package au.com.angryitguy.testsvg;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        }
    }

Voici l'élément VectorDrawable non modifié du site de conception matérielle de Google.

<vector android:height="24dp" android:viewportHeight="24.0"
    android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#FFFFFF" android:pathData="M12,4m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
    <path android:fillColor="#FFFFFF" android:pathData="M19,13v-2c-1.54,0.02 -3.09,-0.75 -4.07,-1.83l-1.29,-1.43c-0.17,-0.19 -0.38,-0.34 -0.61,-0.45 -0.01,0 -0.01,-0.01 -0.02,-0.01L13,7.28c-0.35,-0.2 -0.75,-0.3 -1.19,-0.26C10.76,7.11 10,8.04 10,9.09L10,15c0,1.1 0.9,2 2,2h5v5h2v-5.5c0,-1.1 -0.9,-2 -2,-2h-3v-3.45c1.29,1.07 3.25,1.94 5,1.95zM12.83,18c-0.41,1.16 -1.52,2 -2.83,2 -1.66,0 -3,-1.34 -3,-3 0,-1.31 0.84,-2.41 2,-2.83L9,12.1c-2.28,0.46 -4,2.48 -4,4.9 0,2.76 2.24,5 5,5 2.42,0 4.44,-1.72 4.9,-4h-2.07z"/>
</vector>

Voici mon app build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "au.com.angryitguy.testsvg"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        // Stops the Gradle plugin’s automatic rasterization of vectors
        generatedDensities = []
    }
    // Flag to tell aapt to keep the attribute ids around
    aaptOptions {
        additionalParameters "--no-version-vectors"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.0'
}

Voici le crash. (Notez les erreurs de gonflage qui font référence à la vue de texte.)

java.lang.RuntimeException: Unable to start activity ComponentInfo{
    au.com.angryitguy.testsvg/au.com.angryitguy.testsvg.MainActivity}: 
    android.view.InflateException: Binary XML file line #13: 
    Error inflating class TextView

at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
...

Caused by: android.view.InflateException: 
    Binary XML file line #13: Error inflating class TextView
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129)
at au.com.angryitguy.testsvg.MainActivity.onCreate(MainActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5008)
...

Caused by: android.content.res.Resources$NotFoundException: 
    File res/drawable/ic_accessible_white_36px.xml from drawable resource ID #0x7f02004b
at android.content.res.Resources.loadDrawable(Resources.java:1918)
at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
at android.widget.TextView.<init>(TextView.java:622)
at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:60)
at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:56)
at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:103)
at android.support.v7.app.AppCompatDelegateImplV7.createView(AppCompatDelegateImplV7.java:963)
at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:1022)
at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:675)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:352) 
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267) 
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129) 
at au.com.angryitguy.testsvg.MainActivity.onCreate(MainActivity.java:14) 
at android.app.Activity.performCreate(Activity.java:5008) 
...

Caused by: org.xmlpull.v1.XmlPullParserException:
    Binary XML file line #1: invalid drawable tag vector
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:877)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java:818)
at android.content.res.Resources.loadDrawable(Resources.java:1915)
at android.content.res.TypedArray.getDrawable(TypedArray.java:601) 
at android.widget.TextView.<init>(TextView.java:622) 
at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:60) 
at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:56) 
at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:103) 
at android.support.v7.app.AppCompatDelegateImplV7.createView(AppCompatDelegateImplV7.java:963) 
at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:1022) 
at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44) 
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:675) 
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:352) 
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267) 
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129) 
at au.com.angryitguy.testsvg.MainActivity.onCreate(MainActivity.java:14) 
at android.app.Activity.performCreate(Activity.java:5008) 
...
en colère
la source
Non, vous ne pouvez pas, car les fichiers SVG ne sont pas pris en charge de manière native . Vous devez utiliser un VectorDrawable à la place (qui n'utilise qu'un sous-ensemble des spécifications SVG).
Phantômaxx
2
Pour voir comment utiliser VectorDrawable avec drawableLeft, drawableRight, drawableTop, drawableBottom consultez cette réponse
Behzad Bahmanyar
J'ai trouvé cela fonctionne pour moi: android.jlelse.eu/...
Huy Tower

Réponses:

186

-il possible d'utiliser drawableRight, etc. pour les actifs SVG?

Oui

AppCompatTextView maintenant supports app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompatet app:drawableEndCompatdessinables composés, supportant backported types étirables tels que VectorDrawableCompat.

Incluez ceci dans votre fichier gradle

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

Dans votre vue texte, vous pouvez utiliser

app:drawableLeftCompat
app:drawableStartCompat

Si vous rencontrez des problèmes lors de l'utilisation de app: drawableLeftCompat, app: drawableStartCompat dans les boutons, vous devrez mettre à jour votre bibliothèque pour

androidx.appcompat: appcompat: 1.2.0-alpha01

ils avaient un bug sur

androidx.appcompat: appcompat: 1.1.0-alpha01

vous pouvez voir les documents


Ou si vous ne souhaitez pas encore mettre à jour, alors:

Comme il semble que Google ne fera rien pour résoudre ce problème de sitôt, j'ai dû proposer une solution réutilisable plus solide pour toutes mes applications:

  1. Ajoutez d'abord des attributs TextView personnalisés dans le fichier attrs.xml de votre application "res / values ​​/ attrs.xml" :

    <resources>
        <declare-styleable name="CustomTextView">
            <attr name="drawableStartCompat" format="reference"/>
            <attr name="drawableEndCompat" format="reference"/>
            <attr name="drawableTopCompat" format="reference"/>
            <attr name="drawableBottomCompat" format="reference"/>
        </declare-styleable>
    </resources>
  2. Ensuite, créez une classe TextView personnalisée comme ceci:

    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.drawable.Drawable;
    import android.os.Build;
    import android.support.v7.content.res.AppCompatResources;
    import android.support.v7.widget.AppCompatTextView;
    import android.util.AttributeSet;
    
    public class CustomTextView extends AppCompatTextView {
        public CustomTextView(Context context) {
            super(context);
        }    
        public CustomTextView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initAttrs(context, attrs);
        }
        public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initAttrs(context, attrs);
        }
    
        void initAttrs(Context context, AttributeSet attrs) {
            if (attrs != null) {
                TypedArray attributeArray = context.obtainStyledAttributes(
                        attrs,
                        R.styleable.CustomTextView);
    
                Drawable drawableStart = null;
                Drawable drawableEnd = null;
                Drawable drawableBottom = null;
                Drawable drawableTop = null;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    drawableStart = attributeArray.getDrawable(R.styleable.CustomTextView_drawableStartCompat);
                    drawableEnd = attributeArray.getDrawable(R.styleable.CustomTextView_drawableEndCompat);
                    drawableBottom = attributeArray.getDrawable(R.styleable.CustomTextView_drawableBottomCompat);
                    drawableTop = attributeArray.getDrawable(R.styleable.CustomTextView_drawableTopCompat);
                } else {
                    final int drawableStartId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableStartCompat, -1);
                    final int drawableEndId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableEndCompat, -1);
                    final int drawableBottomId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableBottomCompat, -1);
                    final int drawableTopId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableTopCompat, -1);
    
                    if (drawableStartId != -1)
                        drawableStart = AppCompatResources.getDrawable(context, drawableStartId);
                    if (drawableEndId != -1)
                        drawableEnd = AppCompatResources.getDrawable(context, drawableEndId);
                    if (drawableBottomId != -1)
                        drawableBottom = AppCompatResources.getDrawable(context, drawableBottomId);
                    if (drawableTopId != -1)
                        drawableTop = AppCompatResources.getDrawable(context, drawableTopId);
                }
    
                // to support rtl
                setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, drawableTop, drawableEnd, drawableBottom);
                attributeArray.recycle();
            }
        }
    }
  3. Vous pouvez désormais l'utiliser facilement dans toutes les mises en page grâce à vos attributs personnalisés:

    <YOUR_VIEW_PACKAGE.CustomTextView
        android:id="@+id/edt_my_edit_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:drawableStartCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
        app:drawableEndCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
        app:drawableTopCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
        app:drawableBottomCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
        />
    • Vous pouvez faire la même chose avec Button , EditText et RadioButton car ils sont dérivés de TextView

J'espère que cela t'aides :)

Behzad Bahmanyar
la source
4
Réponse très utile. Quoi qu'il en soit, je recommande également de lire la réponse très complète de Dadou . Retirer vectorDrawables { useSupportLibrary = true }de mon build.gradlecomme cette réponse le suggère a fonctionné pour moi.
Sam
Je l'ai fait et j'ai maintenant le problème suivant: lorsque j'attache le onclick en XML, j'obtiens l'erreur suivante: java.lang.NoSuchMethodException: onClick [class android.view.View]
Ramdane Oualitsen
3
Je ne suis pas d'accord avec la suppression de la vectorDrawables useSupportLibrary = trueligne du gradle. Lorsque vous le supprimez, vous pouvez toujours placer des vecteurs dans vos vues, mais ils sont redimensionnés de la même manière que les png, ce qui signifie qu'ils seront étirés et devenir granuleux. Si vous voulez que les appareils inférieurs à 5.0 / API21 redimensionnent correctement les vecteurs pour qu'ils paraissent nets, vous devez utiliser cette ligne dans le fichier gradle. Mettre cette ligne en invoque l'EDI pour trouver les zones où vous utilisez des vecteurs de manière incorrecte et vous devez ensuite utiliser le app:srcCompatvia XML ou le définir via le code avecVectorDrawableCompat.create()
Heinous Games
Comment ajouter app:drawableEndCompatpour un meilleur support RTL? Cause setCompoundDrawablesRelativeWithIntrinsicBoundsnécessite au moins le niveau 17 d'API.
Dr.jacky
1
Qu'en est-il de la définition du dessinable par programme?
développeur android
77

Cette solution n'est plus correcte. À partir de la version 23.3.0, les dessins vectoriels ne peuvent être chargés que via l'application: srcCompat ou setImageResource ()

Essayez d'envelopper votre vecteur dessiné dans une liste de calques ou un sélecteur:

<TextView
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawableRight="@drawable/ic_accessible_white_wrapped"
    android:background="@color/colorPrimary"
    android:textColor="#FFFFFF"
    android:textSize="22sp"
    android:text="Hello World!"/>

ic_accessible_white_wrapped.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_accessible_white_36px"/>
</layer-list>
Alexandr Shutko
la source
Cela fonctionne bien. Merci .. Mais il semble que vous ne pouvez pas faire référence directement à un SVG dans "android: drawableXXXXX", vous devez l'envelopper dans autre chose.
angryITguy
1
Oui. Vous ne pouvez pas l'utiliser directement. Uniquement en tant qu'application: srcCompat ou encapsulée ou par programmation. Cela a été décrit ici: android-developers.blogspot.ru/2016/02/…
Alexandr Shutko
Ahh ... merci ... je vois le paragraphe auquel vous faites référence. Alors, est-ce toujours un bug s'ils vous disent de ne pas le faire? ;)
angryITguy
1
Je pense que tout est question de compatibilité descendante. Il semble qu'il y ait un problème pour obtenir un support svg complet, alors ils ont fait quelques solutions de contournement ...
Alexandr Shutko
2
@HarishGyanani à partir de la version de support 23.3.0, ce n'est plus un support plus long. Vous devez ajouter plus de commandes dans votre activité: static {if (Build.VERSION.SDK_INT <Build.VERSION_CODES.LOLLIPOP) {AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); }}
Cuong Nguyen
75

Le meilleur moyen que j'ai trouvé:

Drawable leftDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_search);
search.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
Hani
la source
9
Depuis le 25/08/17, c'est la seule chose qui fonctionne pour moi (définir le dessinable par programmation). J'ai utilisé:Drawable drawable = VectorDrawableCompat.create(getResources(), status.getIconResId(), wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null, drawable, null, null);
saiyancoder
2
minSdk pour setCompoundDrawablesWithIntrinsicBoundsest 17 . Sinon, cela fonctionne très bien.
Victor Rendina
1
Son minSdk est 1 et non 17, vous regardez probablement les apis similaires. setCompoundDrawablesWithIntrinsicBounds => minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds => minSdk 17
正宗 白 布鞋
Meilleure solution pour le réglage par programme, +1
Woton Sampaio
Je l'ai utilisé avec BindingAdapters et fonctionne efficacement, merci!
Ric17101
61

Pour compléter certaines des réponses ici: vous pouvez faire fonctionner VectorDrawable commedrawableLeft (etc.), mais cela dépend de la version de la bibliothèque de support et cela a un prix.

Dans quels cas ça marche? J'ai fait ce diagramme pour vous aider (valable pour Support Library 23.4.0 à - au moins - 25.1.0).

Feuille de triche à dessiner

David Ferrand
la source
2
C'est génial mais vous devriez corriger le nom de la méthode dans le bloc statique ensetCompatVectorFromResourcesEnabled
Vikas Patidar
1
La solution setCompatVectorFromResourcesEnabled ne fonctionne pas sur 25.3.1, malheureusement
Ilja S.
From 23.3.0 version vector drawables can only be loaded via app:srcCompat or setImageResource()donc cette solution est obsolète et ne fonctionnera pas
user25
l'activation setCompatVectorFromSourcesEnabled(true)permet de charger des vectordrawables android:backgroundsur Android 4.x. Donc merci! (Vous devez envelopper le vecteur réel dans une seule liste de
calques
14

Aucune des autres réponses n'a fonctionné, voici comment j'ai ajouté un VectorDrawableà un TextView, que vous devriez utiliser VectorDrawableCompat.create()lorsque vous traitez VectorDrawablesci Android L- dessous :

TextView titleTextView = (TextView) viewHolder.getView(android.R.id.text1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
       Drawable leftDrawable = AppCompatResources
                            .getDrawable(context, R.drawable.ic_tickbox);
       titleTextView.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
}
else
{
      //Safely create our VectorDrawable on pre-L android versions. 
       Drawable leftDrawable = VectorDrawableCompat
                            .create(context.getResources(), R.drawable.ic_tickbox, null);
       titleTextView.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
}

Bref, doux et précis!

Sakiboy
la source
Cela a fonctionné pour Android P et le niveau d'API min 26 (cible 28)
MiStr
@MiStr - Il est également rétrocompatible :)
Sakiboy
9

De Google: à partir de la bibliothèque de support Android 23.3.0, les dessins vectoriels de support ne peuvent être chargés que via l'application: srcCompat ou setImageResource ().

http://android-developers.blogspot.ru/2016/02/android-support-library-232.html

Paulzeng
la source
1
cela signifie aucune solution pour le moment
Killer
Essayez d'encapsuler votre vecteur dessinable dans la liste des calques ou le sélecteur: <TextView android: id = "@ + id / textView" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: drawableRight = "@ drawable / ic_accessible_white_wrapped" android: background = "@ color / colorPrimary" android: textColor = "# FFFFFF" android: textSize = "22sp" android: text = "Hello World!" /> ic_accessible_white_wrapped.xml: <layer-list xmlns: android = " schémas .android.com / apk / res / android "> <item android: drawable =" @ drawable / ic_accessible_white_36px "/> </layer-list>
Exception de pointeur nul
9

Il est possible de définir directement des dessins vectoriels en XML, mais vous avez inclus le framework de liaison de données.

Ecrivez

<TextView
...
android:drawableRight="@{@drawable/ic_accessible_white_36px}"/>

et enveloppez votre mise en page entière dans une <layout>balise, donc fondamentalement votre xml ressemblerait à:

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="au.com.angryitguy.testsvg.MainActivity">


        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:drawableRight="@{@drawable/ic_accessible_white_36px}"
            android:text="Hello World!"
            android:textColor="#FFFFFF"
            android:textSize="22sp"/>
    </RelativeLayout>
</layout>

Pour activer le cadre de liaison de données, ajoutez simplement

android {
    ....
    defaultConfig {
        dataBinding {
            enabled = true
        }
    }
}

Vous n'avez pas besoin d'utiliser d'autres fonctionnalités de la bibliothèque de liaison

ÉDITER:

Bien sûr, si vous souhaitez utiliser des dessins vectoriels pré-Lollipop, vous devez activer les dessins vectoriels de support en utilisant

vectorDrawables.useSupportLibrary = true

Donc, vous avez build.gradlebesoin de 2 nouvelles commandes:

android {
    ....
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
        dataBinding {
            enabled = true
        }
    }
}

merci à rkmax pour la remarque

Hans M
la source
C'est une bonne idée, mais vous devez écrire un adaptateur de liaison pour que cela fonctionne. Voici un exemple de travail: gist.github.com/lisawray/78c33f76809d2bcbbec9983e2c141a70
BladeCoder
1
Je dois dire que cela fonctionne pour moi mais vous devez activer vectorDrawables.useSupportLibrarysur app / build.gradle et également ajouter AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) sur l'activité
rkmax
J'ai oublié d'ajouter defaultConfig dans le build.gradlequi pourrait être la raison pour laquelle cela ne fonctionne pas
Hans M
Merci - vous sauvez la vie!
Van
C'est une réponse sous-estimée!
DYS
6

J'ai parcouru toutes les réponses et en utilisant le dernier studio Android 3.0.1 et la bibliothèque de support AppCompat 26.1.0, je peux vous assurer que cela fonctionne très bien.

Dans le fichier build.gradle (app)

android {
    compileSdkVersion 26
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

dependencies {
    implementation 'com.android.support:appcompat-v7:26.1.0'
}

Et dans l'extension d'activité, AppcompatActivityincluez ces méthodes extérieures, c'est-à-dire un staticbloc

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}  

ou si vous voulez que cela soit appliqué à l'ensemble de l'application, incluez simplement cette ligne dans la classe d'extension de Applicationclasse

override fun onCreate() {
    super.onCreate()
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
}

Textview en xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical">

<TextView
        android:id="@+id/passName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawableLeft="@drawable/account_drawableleft_selector"
        android:drawablePadding="5dp"
        android:ellipsize="marquee"
        android:fontFamily="@font/montserrat_light_family"
        android:gravity="center_vertical"
        android:marqueeRepeatLimit="marquee_forever"
        android:paddingRight="10dp"
        android:scrollHorizontally="true"
        android:singleLine="true"
        android:textColor="@color/app_text_color"
        android:textSize="12sp"
        tools:text="Account Name" />
</LinearLayout>

account_drawableleft_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_account_circle_24dp" /> <!-- checked -->
</selector>
Amit Tumkur
la source
Fonctionne bien sur quelle API? Avez-vous essayé le 19 ou le 20?
Divers
Pouvez-vous montrer comment vous utilisez drawableRightpour TextViewen XML?
Divers
2
comme quelques-uns mentionnés ci-dessus, si vous utilisez le vecteur xml directement comme drawableLeft, vous obtenez toujours ce plantage ou cette exception, donc la solution de contournement consiste à utiliser ce vecteur xml comme sélecteur pour drawableLeft pour Textview. Utilisation que vous pouvez voir dans la réponse modifiée.
Amit Tumkur
1
cela ne fonctionnera pas, vous ne pouvez pas utiliser de dessin vectoriel pour TextView directement en xml
user25
Testez-le dans l'API 19 et 20. J'ai utilisé AppCompatDelegate.setCompatVectorFromResourcesEnabled dans la classe d'application à la place. Travailler comme un charme!
Red M
5

Je suis si tard pour répondre à cette question que je suis resté en retard avec ce problème. J'ai eu le même problème avec les drawables svg / vector avec TextView. Au lieu de créer votre propre dessin personnalisé, je suis en mesure de résoudre mon problème avec 2 lignes de code comme ci-dessous:

Drawable drawableTop = AppCompatResources.getDrawable(view.getContext(), iconId);
view.setCompoundDrawablesWithIntrinsicBounds(null, drawableTop, null, null);

J'espère que cela vous aidera.

Rahul Sharma
la source
Non compatible avec les Lappareils pré .
Sakiboy
@Sakiboy Oui, car j'utilise ce code avec un api minimum 17.
Rahul Sharma
Ne fonctionne pas avec VectorDrawablestous les appareils exécutant pré-L, il suffit de dire. Soyez prudent lorsque vous utilisez cette réponse, car il existe des API plus sûres et plus précises à utiliser.
Sakiboy
4

J'ai conçu une petite bibliothèque pour cela - textview-rich-drawable (elle prend également en charge la définition de la taille et de la teinte des composés).

<com.tolstykh.textviewrichdrawable.TextViewRichDrawable
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Some text"
    app:compoundDrawableHeight="24dp"
    app:compoundDrawableWidth="24dp"
    app:drawableTopVector="@drawable/some_vector_drawble"
    app:drawableEndVector="@drawable/another_vector_drawable"
    app:drawableTint="@color/colorAccent" />

Et la dépendance

compile 'com.tolstykh.textviewrichdrawable:textview-rich-drawable:0.3.2'

entrez la description de l'image ici

Oleksandr
la source
3

Si vous utilisez la liaison, il existe un autre moyen magique d'utiliser la même approche pour utiliser des vecteurs dans un TextView. Les emballer comme:

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

Cela fonctionnera comme par magie, je n'ai pas enquêté sur ce qui se passe dans les coulisses, mais je suppose que TextView utilise la getDrawableméthode du AppCompatResourcesou similaire.

cesards
la source
2

Sur la base de la réponse de Behzad Bahmanyar , j'ai remarqué que je ne pouvais pas utiliser les attributs normaux d'Android pour les fichiers png normaux:

android:drawableTop
android:drawableBottom
etc

car il serait remplacé par null dans

Drawable drawableTop = null;
...
setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, drawableTop, drawableEnd, drawableBottom);

si le app:drawableTopCompatn'était pas défini, mais l' android:drawableTopétait (par exemple).

Voici la solution complète:

public class CustomTextView extends AppCompatTextView {
    private static final int NOT_SET = -1;
    private static final int LEFT = 0;
    private static final int START = 0;
    private static final int TOP = 1;
    private static final int RIGHT = 2;
    private static final int END = 2;
    private static final int BOTTOM = 3;

    public CustomTextView(Context context) {
        super(context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
    }

    void initAttrs(Context context, AttributeSet attrs) {
        if (attrs == null) {
            return;
        }
        Drawable[] drawablesArr = getCompoundDrawables();

        TypedArray attributeArray = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        Drawable drawableStart = null;
        Drawable drawableEnd = null;
        Drawable drawableBottom = null;
        Drawable drawableTop = null;
        Drawable drawableLeft = null;
        Drawable drawableRight = null;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            drawableStart = attributeArray.getDrawable(R.styleable.CustomTextView_drawableStartCompat);
            drawableEnd = attributeArray.getDrawable(R.styleable.CustomTextView_drawableEndCompat);
            drawableBottom = attributeArray.getDrawable(R.styleable.CustomTextView_drawableBottomCompat);
            drawableTop = attributeArray.getDrawable(R.styleable.CustomTextView_drawableTopCompat);
            drawableLeft = attributeArray.getDrawable(R.styleable.CustomTextView_drawableLeftCompat);
            drawableRight = attributeArray.getDrawable(R.styleable.CustomTextView_drawableRightCompat);
        } else {
            final int drawableStartId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableStartCompat, NOT_SET);
            final int drawableEndId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableEndCompat, NOT_SET);
            final int drawableBottomId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableBottomCompat, NOT_SET);
            final int drawableTopId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableTopCompat, NOT_SET);
            final int drawableLeftId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableLeftCompat, NOT_SET);
            final int drawableRightId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableRightCompat, NOT_SET);

            if (drawableStartId != NOT_SET)
                drawableStart = AppCompatResources.getDrawable(context, drawableStartId);
            if (drawableLeftId != NOT_SET)
                drawableLeft = AppCompatResources.getDrawable(context, drawableLeftId);
            if (drawableEndId != NOT_SET)
                drawableEnd = AppCompatResources.getDrawable(context, drawableEndId);
            if (drawableRightId != NOT_SET)
                drawableRight = AppCompatResources.getDrawable(context, drawableRightId);
            if (drawableBottomId != NOT_SET)
                drawableBottom = AppCompatResources.getDrawable(context, drawableBottomId);
            if (drawableTopId != NOT_SET)
                drawableTop = AppCompatResources.getDrawable(context, drawableTopId);
        }

        drawableStart = (drawableStart != null ? drawableStart : drawablesArr[START]);
        drawableLeft = (drawableLeft != null ? drawableLeft : drawablesArr[LEFT]);
        drawableStart = (drawableStart != null ? drawableStart : drawableLeft);

        drawableEnd = (drawableEnd != null ? drawableEnd : drawablesArr[END]);
        drawableRight = (drawableRight != null ? drawableRight : drawablesArr[RIGHT]);
        drawableEnd = (drawableEnd != null ? drawableEnd : drawableRight);

        drawableBottom = (drawableBottom != null ? drawableBottom : drawablesArr[BOTTOM]);
        drawableTop = (drawableTop != null ? drawableTop : drawablesArr[TOP]);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, drawableTop, drawableEnd, drawableBottom);
        } else {
            setCompoundDrawables(drawableStart, drawableTop, drawableEnd, drawableBottom);
        }

        attributeArray.recycle();
    }
}
Goran Horia Mihail
la source
Cela devrait être une réponse acceptée. fonctionne avec les fichiers png normaux et les attributs drawableTop, drawableBottom. La réponse acceptée ne fonctionne pas avec les attributs de fichier png et drawableTop, drawableBottom.
Bhargav Pandya
2

Dans le fichier build.gradle (app)

android {
    compileSdkVersion 26
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }

    dataBinding {
        enabled = true
    }
}

...

public class BindingUtils {
    @BindingAdapter("android:drawableRight")
    public static void setDrawableStart(TextView textView, int resourceId) {
        Drawable drawable = AppCompatResources.getDrawable(textView.getContext(), resourceId);
        Drawable[] drawables = textView.getCompoundDrawables();
        textView.setCompoundDrawablesWithIntrinsicBounds(drawable,
                drawables[1], drawables[2], drawables[3]);
    } 
}

use (lors de la liaison de données)

android:drawableRight="@{viewModel.ResId}"

Ou (normal)

android:drawableRight="@{@drawable/ic_login_24dp}"
Ahmad Aghazadeh
la source
1

Utilisation de l'utilisation de Vector Drawables

Kotlin

 val drawable1 = VectorDrawableCompat.create(resources, R.drawable.ic_rb_username, theme)
        yourView.setCompoundDrawablesRelativeWithIntrinsicBounds( drawable1, null, null, null)

Java

  Drawable drawable1 = VectorDrawableCompat.create(getResources(), R.drawable.ic_rb_username, getTheme());
        yourView.setCompoundDrawablesRelativeWithIntrinsicBounds( drawable1, null, null, null);
Marge
la source
1

Pour une compatibilité descendante, utilisez:

TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, left, top, right, bottom)
Shayan_Aryan
la source
0

J'utilise un adaptateur de liaison pour résoudre ce problème

@JvmStatic
@BindingAdapter("drawableSvgLeft")
fun addDrawableSvgLeft(textView: TextView,drawable: Drawable){
    textView.setCompoundDrawablesWithIntrinsicBounds(drawable,null,null,null)
}

@JvmStatic
@BindingAdapter("drawableSvgRight")
fun addDrawableSvgRight(textView: TextView,drawable: Drawable){
    textView.setCompoundDrawablesWithIntrinsicBounds(null,null,drawable,null)
}

et aussi en utilisant de cette manière dans ma mise en page

<TextView
  drawableSvgRight="@{@drawable/svg_ic_battle_trophy}"
  .....

probablement vectorDrawables.useSupportLibrary = true dans la configuration par défaut est nécessaire

mahdi ZTD
la source