È possibile utilizzare VectorDrawable in Buttons e TextView utilizzando android: DrawableRight?


120

Quando utilizzo le risorse VectorDrawable in una visualizzazione di testo o visualizzazione di immagini, si verifica un arresto anomalo del runtime quando si utilizza "android: DrawableRight" / "android: DrawableEnd" / "android: DrawableStart" / "android: DrawableLeft".

L'app verrà compilata correttamente senza alcun avviso.

sto usando

  • Gradle 1.5
  • Libreria di supporto 23.2 ("com.android.support:appcompat-v7:23.2.0")

Quello che ho scoperto però è che posso assegnare programmaticamente SVG in Java senza arresti anomali come questo.

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

(Sospetto che questo sia un bug della libreria di supporto per 23.2.)

Ma è possibile utilizzare DrawableRight ecc. Per le risorse SVG?

Ecco il mio layout

<?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>

Ecco la mia attività

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

        }
    }

Ecco l'asset VectorDrawable non modificato dal sito di material design di 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>

Ecco la mia 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'
}

Ecco l'incidente. (Nota gli errori di gonfiaggio che fanno riferimento alla visualizzazione di testo.)

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) 
...

No, non puoi, poiché i file SVG non sono supportati in modo nativo . Devi usare un VectorDrawable, invece (che usa solo un sottoinsieme delle specifiche SVG).
Phantômaxx

2
Per vedere come utilizzare VectorDrawable con drawableLeft, drawableRight, drawableTop, drawableBottom controlla questa risposta
Behzad Bahmanyar

Ho trovato che funziona per me: android.jlelse.eu/…
Huy Tower

Risposte:


186

è possibile utilizzare drawableRight ecc per le risorse SVG?

AppCompatTextView ora supporti app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompate app:drawableEndCompatdrawable composti, supportante backported tipi disegnabili come VectorDrawableCompat.

Includilo nel tuo file gradle

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

Nella visualizzazione del testo puoi usare

app:drawableLeftCompat
app:drawableStartCompat

Se hai problemi durante l'utilizzo di app: drawableLeftCompat, app: drawableStartCompat nei pulsanti dovrai aggiornare la tua libreria a

androidx.appcompat: appcompat: 1.2.0-alpha01

avevano un bug su

androidx.appcompat: appcompat: 1.1.0-alpha01

puoi vedere i documenti


Oppure, se non desideri ancora eseguire l'aggiornamento, allora:

Poiché sembra che Google non farà nulla al riguardo in qualunque momento presto, ho dovuto trovare una soluzione riutilizzabile più solida per tutte le mie app:

  1. Per prima cosa aggiungi attributi TextView personalizzati nel file attrs.xml della tua app "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. Quindi crea una classe TextView personalizzata come questa:

    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. Ora puoi usarlo facilmente in qualsiasi layout tramite i tuoi attributi personalizzati:

    <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 -->
        />
    
    • Puoi fare una cosa simile con Button , EditText e RadioButton perché derivano da TextView

Spero che questo ti aiuti :)


4
Risposta molto utile. Comunque, consiglio di leggere anche la risposta molto completa di Dadou . Rimuovere vectorDrawables { useSupportLibrary = true }dal mio build.gradleperché quella risposta suggerisce che ha funzionato per me.
Sam

L'ho fatto e ora ho il seguente problema: quando allego onclick in XML ottengo il seguente errore: java.lang.NoSuchMethodException: onClick [class android.view.View]
Ramdane Oualitsen

3
Non sono d'accordo con la rimozione della vectorDrawables useSupportLibrary = truelinea dal gradle. Quando lo rimuovi, puoi ancora inserire i vettori nelle tue viste, ma si ridimensionano allo stesso modo dei png, il che significa che verranno allungati e diventeranno granulosi. Se desideri che i dispositivi inferiori a 5.0 / API21 ridimensionino effettivamente i vettori correttamente in modo che appaiano nitidi, devi utilizzare quella linea all'interno del file gradle. Inserendo quella linea si richiama l'IDE per trovare le aree in cui si stanno utilizzando i vettori in modo errato e quindi è necessario utilizzare app:srcCompattramite XML o impostarlo tramite codice conVectorDrawableCompat.create()
Heinous Games

Come aggiungere app:drawableEndCompatper un migliore supporto RTL? La causa setCompoundDrawablesRelativeWithIntrinsicBoundsrichiede almeno il livello API 17.
Dr.jacky

1
Che ne dici di impostare il drawable a livello di programmazione?
sviluppatore Android

77

Questa soluzione non è più corretta. Dalla versione 23.3.0 i drawable vettoriali possono essere caricati solo tramite app: srcCompat o setImageResource ()

Prova ad avvolgere il tuo vettore disegnabile in un elenco di livelli o un selettore:

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

Funziona bene. Grazie .. Ma sembra che non puoi fare riferimento direttamente a un SVG in "android: drawableXXXXX" devi racchiuderlo in qualcos'altro.
angryITguy

1
Sì. Non puoi usarlo direttamente. Solo come app: srcCompat o wrapping o a livello di codice. Questo è stato descritto qui: android-developers.blogspot.ru/2016/02/…
Alexandr Shutko

Ahh .. grazie .. vedo il paragrafo a cui ti riferisci. Quindi, è ancora un bug se ti dicono di non farlo? ;)
angryITguy

1
Penso che sia tutta una questione di compatibilità con le versioni precedenti. Sembra che ci sia qualche problema per ottenere il supporto svg completo, quindi hanno fatto alcune soluzioni alternative ...
Alexandr Shutko

2
@ HarishGyanani dalla versione di supporto 23.3.0, non è un supporto più lungo. Devi aggiungere più comandi nella tua attività: static {if (Build.VERSION.SDK_INT <Build.VERSION_CODES.LOLLIPOP) {AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); }}
Cuong Nguyen

75

Il modo migliore che ho trovato:

Drawable leftDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_search);
search.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

9
A partire dal 25/8/17 questa è l'unica cosa che funziona per me (impostando il disegnabile a livello di programmazione). In realtà ho usato:Drawable drawable = VectorDrawableCompat.create(getResources(), status.getIconResId(), wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null, drawable, null, null);
saiyancoder

2
minSdk per setCompoundDrawablesWithIntrinsicBoundsè 17 . Altrimenti funziona benissimo.
Victor Rendina

1
Il suo minSdk è 1 non 17, probabilmente guardi l'api simile. setCompoundDrawablesWithIntrinsicBounds => minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds => minSdk 17
正宗 白 布鞋

La migliore soluzione per l'impostazione programmatica, +1
Woton Sampaio

L'ho usato con BindingAdapters e funziona in modo efficace, grazie!
Ric17101

61

Per completare alcune delle risposte qui: puoi far funzionare VectorDrawable come drawableLeft(ecc.) Ma dipende dalla versione della libreria di supporto e ha un prezzo.

In quali casi funziona? Ho creato questo diagramma per aiutare (valido per la libreria di supporto da 23.4.0 a - almeno - 25.1.0).

VectorDrawable cheatsheet


2
È fantastico, ma dovresti correggere il nome del metodo nel blocco statico insetCompatVectorFromResourcesEnabled
Vikas Patidar

1
La soluzione setCompatVectorFromResourcesEnabled non funziona su 25.3.1, sfortunatamente
Ilja S.

From 23.3.0 version vector drawables can only be loaded via app:srcCompat or setImageResource()quindi questa soluzione è deprecata e non funzionerà
user25

l'abilitazione setCompatVectorFromSourcesEnabled(true)rende possibile il caricamento di vectordrawables android:backgroundsu Android 4.x. Quindi grazie! (È necessario racchiudere il vettore effettivo in un singolo elenco di livelli di elementi)
Peterdk

14

Nessuna delle altre risposte ha funzionato, ecco come ho aggiunto un VectorDrawablea a TextView, dovresti usare VectorDrawableCompat.create()quando hai a che fare con di VectorDrawablesseguito Android L:

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

Breve, dolce e al punto!



@MiStr - È anche retrocompatibile :)
Sakiboy

9

Da Google: a partire dalla libreria di supporto Android 23.3.0, i drawable dei vettori di supporto possono essere caricati solo tramite app: srcCompat o setImageResource () ..

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


1
ciò significa nessuna soluzione per ora
Killer

Prova a racchiudere il tuo disegno vettoriale in un elenco di livelli o un selettore: <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 = " schemas .android.com / apk / res / android "> <item android: drawable =" @ drawable / ic_accessible_white_36px "/> </layer-list>
Eccezione puntatore nullo

9

È possibile impostare direttamente i drawable vettoriali in xml, ma è stato incluso il framework di data binding.

Scrivi e basta

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

e avvolgi l'intero layout in un <layout>tag, quindi in pratica il tuo xml sarebbe simile a:

<?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>

Per attivare il framework di data binding basta aggiungere

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

Non è necessario utilizzare altre funzionalità della libreria di binding

MODIFICARE:

Ovviamente se vuoi usare i drawable vettoriali pre-Lollipop devi abilitare i drawable vettoriali di supporto usando

vectorDrawables.useSupportLibrary = true

Quindi hai build.gradlebisogno di 2 nuovi comandi:

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

grazie a rkmax per il commento


Questa è una buona idea, ma è necessario scrivere un adattatore di associazione affinché funzioni. Ecco un esempio funzionante: gist.github.com/lisawray/78c33f76809d2bcbbec9983e2c141a70
BladeCoder

1
Devo dire che per me funziona, ma devi abilitare vectorDrawables.useSupportLibrarysu app / build.gradle e aggiungere anche AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) sull'attività
rkmax

Ho dimenticato di aggiungere defaultConfig in build.gradlequesto potrebbe essere il motivo per cui non funziona
Hans M

Grazie - sei un salvavita!
Van

Questa è una risposta sottovalutata!
DYS

6

Ho esaminato tutte le risposte e utilizzando l'ultima versione di Android Studio 3.0.1 e la libreria di supporto AppCompat 26.1.0 posso assicurare che funziona bene.

Nel file build.gradle (app)

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

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

E in Activity extending AppcompatActivityincludi questi metodi esterni, cioè un staticblocco

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}  

o se vuoi che questo venga applicato all'intera app includi semplicemente questa riga all'interno della classe che estende la Applicationclasse

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

Textview in 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>

Funziona bene su quale API? Hai provato il 19 o il 20?
Subacquei

Puoi mostrare come usi drawableRightper TextViewin XML?
Subacquei

2
come alcuni menzionati sopra, se usi il vettore xml direttamente come drawableLeft ottieni ancora questo arresto anomalo o eccezione, quindi la soluzione alternativa è usare quel vettore xml come selettore per drawableLeft per Textview. Utilizzo che puoi vedere nella risposta modificata.
Amit Tumkur

1
non funzionerà, non è possibile utilizzare il disegno vettoriale per TextView direttamente in xml
user25

Provalo nell'API 19 e 20. Ho usato invece AppCompatDelegate.setCompatVectorFromResourcesEnabled nella classe dell'applicazione. Funziona come un fascino!
Red M


5

Sono così in ritardo per rispondere a questa domanda perché sono rimasto bloccato in ritardo con questo problema. Ho avuto lo stesso problema con svg / vector drawables con TextView. Invece di creare il tuo disegnabile personalizzato, sono in grado di risolvere il mio problema con 2 righe di codice come di seguito:

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

Spero che ti possa aiutare.


Non compatibile con i Ldispositivi pre .
Sakiboy

@Sakiboy Sì, sto usando questo codice con un minimo di api 17.
Rahul Sharma

Non funziona con VectorDrawablessu tutti i dispositivi che eseguono pre-L, solo sayin. Fai attenzione quando usi questa risposta, poiché ci sono API più sicure e accurate da usare.
Sakiboy

4

Ho progettato una piccola libreria per questo - textview-rich-drawable (supporta anche la definizione delle dimensioni e della colorazione dei drawables composti).

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

E la dipendenza

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

inserisci qui la descrizione dell'immagine


3

Se stai usando l'associazione, c'è un altro modo magico per avere lo stesso approccio per usare i vettori in un TextView. Incartandoli come:

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

Magicamente funzionerà, non ho indagato su cosa sta succedendo dietro le quinte, ma immagino che TextView stia usando il getDrawablemetodo di AppCompatResourceso simili.


2

Sulla base della risposta di Behzad Bahmanyar , ho notato che non potevo usare gli attributi normali di Android per i normali file png:

android:drawableTop
android:drawableBottom
etc

perché verrebbe sostituito con null in

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

se app:drawableTopCompatnon è stato impostato, ma è android:drawableTopstato (ad esempio).

Ecco la soluzione completa:

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

Questa dovrebbe essere una risposta accettata. funziona con normali file png e attributi drawableTop, drawableBottom. La risposta accettata non funziona con il file png e gli attributi drawableTop, drawableBottom.
Bhargav Pandya

2

Nel file 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]);
    } 
}

utilizzare (durante l'associazione dati)

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

Oppure (normale)

android:drawableRight="@{@drawable/ic_login_24dp}"

1

Utilizzando Vector Drawables usa

Kotlin

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

Giava

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

1

Per la compatibilità con le versioni precedenti, utilizzare:

TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, left, top, right, bottom)

0

Sto usando l'adattatore di rilegatura per risolvere questo problema

@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)
}

e anche utilizzando in questo modo nel mio layout

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

probabilmente vectorDrawables.useSupportLibrary = true nella configurazione predefinita è necessario

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.