¿Es posible usar VectorDrawable en Buttons y TextViews usando android: DrawableRight?

120

Cuando uso los recursos de VectorDrawable en una vista de texto o una vista de imagen, obtengo un bloqueo en tiempo de ejecución al usar "android: DrawableRight" / "android: DrawableEnd" / "android: DrawableStart" / "android: DrawableLeft".

La aplicación se compilará bien sin advertencias.

estoy usando

  • Gradle 1.5
  • Biblioteca de soporte 23.2 ('com.android.support:appcompat-v7:23.2.0')

Sin embargo, lo que he encontrado es que puedo asignar SVG programáticamente en Java sin fallas como esta.

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

(Sospecho que este es un error de la biblioteca de soporte para 23.2.)

¿Pero es posible usar drawableRight, etc. para los activos de SVG?

Aquí está mi diseño

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

Aquí está mi actividad

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

        }
    }

Aquí está el activo VectorDrawable no modificado del sitio de diseño de materiales 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>

Aquí está mi aplicación 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'
}

Aquí está el choque. (Tenga en cuenta los errores de inflado que hacen referencia a la vista de texto).

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) 
...
angryITguy
fuente
No, no puede, ya que los archivos SVG no son compatibles de forma nativa . En su lugar, debe usar un VectorDrawable (que solo usa un subconjunto de las especificaciones SVG).
Phantômaxx
2
Para ver cómo usar VectorDrawable con drawableLeft, drawableRight, drawableTop, drawableBottom echa un vistazo a esta respuesta
Behzad Bahmanyar
Encontré que esto funciona para mí: android.jlelse.eu/…
Huy Tower

Respuestas:

186

¿Es posible utilizar drawableRight, etc. para los activos de SVG?

si

AppCompatTextView ahora soportes app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompaty app:drawableEndCompatdibujables compuestos, apoyando portado tipos estirables tales como VectorDrawableCompat.

Incluya esto en su archivo gradle

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

En su vista de texto puede usar

app:drawableLeftCompat
app:drawableStartCompat

Si tiene problemas al usar la aplicación: drawableLeftCompat, app: drawableStartCompat en los botones, deberá actualizar su biblioteca a

androidx.appcompat: appcompat: 1.2.0-alpha01

tenían un error

androidx.appcompat: appcompat: 1.1.0-alpha01

puedes ver los documentos


O si aún no desea actualizar, entonces:

Debido a que parece que Google no va a hacer nada al respecto en el corto plazo, tuve que encontrar una solución reutilizable más sólida para todas mis aplicaciones:

  1. Primero agregue atributos personalizados de TextView en el archivo attrs.xml de su aplicación "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. Luego cree una clase TextView personalizada como esta:

    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. Ahora puede usarlo fácilmente en cualquier diseño según sus atributos personalizados:

    <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 -->
        />
    • Puede hacer algo similar con Button , EditText y RadioButton porque derivan de TextView

Espero que esto ayude :)

Behzad Bahmanyar
fuente
44
Muy útil respuesta. De todos modos, recomiendo leer la respuesta muy completa de Dadou también. Eliminar vectorDrawables { useSupportLibrary = true }de mi build.gradlecomo esa respuesta sugiere funcionó para mí.
Sam
Lo hice y ahora tengo el siguiente problema: cuando adjunto el onclick en XML obtengo el siguiente error: java.lang.NoSuchMethodException: onClick [class android.view.View]
Ramdane Oualitsen
3
No estoy de acuerdo con la eliminación de la vectorDrawables useSupportLibrary = truelínea de la gradle. Cuando lo eliminas, aún puedes poner vectores dentro de tus vistas, pero cambian de tamaño de la misma manera que pngs, lo que significa que se estirarán y se volverán granulados. Si desea que los dispositivos por debajo de 5.0 / API21 cambien el tamaño de los vectores correctamente para que se vean nítidos, debe usar esa línea dentro del archivo gradle. Poner esa línea invoca el IDE para encontrar áreas en las que está utilizando vectores incorrectamente y luego debe usar el app:srcCompatcódigo XML o configurarlo a través del código conVectorDrawableCompat.create()
Heinous Games
¿Cómo agregar app:drawableEndCompatpara un mejor soporte RTL? Causa setCompoundDrawablesRelativeWithIntrinsicBoundsnecesita API nivel 17 al menos.
Dr.jacky
1
¿Qué pasa con la configuración del dibujo mediante programación?
Desarrollador de Android el
77

Esta solución ya no es correcta. A partir de la versión 23.3.0, los dibujos vectoriales solo se pueden cargar a través de la aplicación: srcCompat o setImageResource ()

Intente ajustar su vector dibujable en lista de capas o selector:

<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
fuente
Esto funciona bien Gracias ... Pero parece que no puedes referirte directamente a un SVG en "android: drawableXXXXX", tienes que envolverlo en otra cosa.
angryITguy
1
Si. No puedes usarlo directamente. Solo como aplicación: srcCompat o envuelto o mediante programación. Esto se describió aquí: android-developers.blogspot.ru/2016/02/…
Alexandr Shutko
Ahh ... gracias ... puedo ver el párrafo al que te refieres. Entonces, ¿sigue siendo un error si te dicen que no lo hagas? ;)
angryITguy
1
Creo que se trata de compatibilidad con versiones anteriores. Parece que hay algún problema para obtener soporte svg completo, por lo que hicieron algunas soluciones ...
Alexandr Shutko
2
@HarishGyanani de la versión de soporte 23.3.0, ya no es soporte. Debe agregar más comandos en su actividad: static {if (Build.VERSION.SDK_INT <Build.VERSION_CODES.LOLLIPOP) {AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); }}
Cuong Nguyen
75

La mejor manera que encontré:

Drawable leftDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_search);
search.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
Hani
fuente
9
A partir del 25/08/17, esto es lo único que funciona para mí (establecer el dibujo mediante programación). Yo realmente utilizadas:Drawable drawable = VectorDrawableCompat.create(getResources(), status.getIconResId(), wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null, drawable, null, null);
saiyancoder
2
minSdk para setCompoundDrawablesWithIntrinsicBoundses 17 . De lo contrario, esto funciona muy bien.
Victor Rendina
1
Su minSdk es 1, no 17, es probable que se parezca a las API similares. setCompoundDrawablesWithIntrinsicBounds => minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds => minSdk 17
正宗 白 布鞋
La mejor solución para la configuración programática, +1
Woton Sampaio
Usé esto con BindingAdapters y funciona de manera efectiva, ¡gracias!
Ric17101
61

Para complementar algunas de las respuestas aquí: puede hacer que VectorDrawable funcione como drawableLeft(etc.) pero depende de la versión de la Biblioteca de soporte y tiene un precio.

¿En qué casos funciona? He creado este diagrama para ayudar (válido para Support Library 23.4.0 a - al menos - 25.1.0).

VectorDrawable Cheatsheet

David Ferrand
fuente
2
Es genial, pero debe corregir el nombre del método en bloque estático parasetCompatVectorFromResourcesEnabled
Vikas Patidar
1
La solución setCompatVectorFromResourcesEnabled no funciona en 25.3.1, desafortunadamente
Ilja S.
From 23.3.0 version vector drawables can only be loaded via app:srcCompat or setImageResource()por lo que esta solución está en desuso y no funcionará
user25
la habilitación setCompatVectorFromSourcesEnabled(true)permite cargar vectores dibujables en android:backgroundAndroid 4.x. ¡Así que gracias! (
Debe
14

Ninguna de las otras respuestas funcionó, así es como agregué una VectorDrawablea TextView, debe usarla VectorDrawableCompat.create()al tratar a VectorDrawablescontinuación 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);
}

¡Corto, dulce y al punto!

Sakiboy
fuente
Esto funcionó para Android P, y el nivel mínimo de API 26 (objetivo 28)
MiStr
@MiStr - También es compatible con versiones anteriores :)
Sakiboy
9

Desde Google: a partir de Android Support Library 23.3.0, los dibujos vectoriales de soporte solo se pueden cargar a través de la aplicación: srcCompat o setImageResource () ..

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

Paulzeng
fuente
1
eso significa que no hay solución por ahora
Killer
Intente ajustar su vector dibujable en lista de capas o selector: <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 = " esquemas .android.com / apk / res / android "> <item android: drawable =" @ drawable / ic_accessible_white_36px "/> </layer-list>
Excepción de puntero nulo el
9

Es posible establecer directamente dibujos vectoriales en xml, pero debe incluir el marco de enlace de datos.

Solo escribe

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

y envuelva todo su diseño en una <layout>etiqueta, por lo que básicamente su xml se vería así:

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

Para activar el marco de enlace de datos simplemente agregue

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

No tiene que usar ninguna otra característica de la biblioteca de enlace

EDITAR:

Por supuesto, si desea usar dibujos vectoriales dibujables antes de Lollipop, debe habilitar el soporte de dibujos vectoriales usando

vectorDrawables.useSupportLibrary = true

Por lo tanto, build.gradlenecesita 2 nuevos comandos:

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

gracias a rkmax por el comentario

Hans M
fuente
Esta es una buena idea, pero necesita escribir un adaptador de enlace para que esto funcione. Aquí hay un ejemplo de trabajo: gist.github.com/lisawray/78c33f76809d2bcbbec9983e2c141a70
BladeCoder
1
Debo decir que esto funciona para mí, pero debe habilitarlo vectorDrawables.useSupportLibraryen app / build.gradle y también agregar AppCompatDelegate.setCompatVectorFromResourcesEnabled (verdadero) en la actividad
rkmax
Olvidé agregar defaultConfig en la build.gradleque podría ser la razón por la que no está funcionando
Hans M
Gracias, eres un salvavidas!
Van
Esta es una respuesta subestimada!
DYS
6

Revisé todas las respuestas y utilicé la última versión de Android Studio 3.0.1 y AppCompat Support Library 26.1.0. Puedo asegurar que esto funciona bien.

En el archivo build.gradle (aplicación)

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

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

Y en la extensión de actividad, AppcompatActivityincluya estos métodos externos, es decir, un staticbloque

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}  

o si desea que esto se aplique a toda la aplicación, simplemente incluya esta línea dentro de la clase que extiende la Applicationclase

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

Vista de texto 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
fuente
¿Funciona bien en qué API? ¿Te probaste el 19 o el 20?
Buzos
Se puede mostrar cómo se utiliza drawableRightpara TextViewen XML?
Buzos
2
como algunos mencionados anteriormente, si usa el vector xml directamente como drawableLeft, todavía tiene este bloqueo o excepción, por lo tanto, la solución es usar ese vector xml como un selector para drawableLeft para Textview. Uso que puede ver en la respuesta editada.
Amit Tumkur
1
no va a funcionar, no puede usar el dibujo vectorial para TextView directamente en xml
user25
Pruébelo en API 19 y 20. En su lugar, usé AppCompatDelegate.setCompatVectorFromResourcesEnabled en la clase de aplicación. Trabajando como un encanto!
Red M
5

Llegué tan tarde a responder esta pregunta que me atrapé tarde con este problema. Tuve el mismo problema con svg / vector drawables con TextView. En lugar de hacer su propio dibujo personalizado, puedo solucionar mi problema con 2 líneas de código de la siguiente manera:

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

Espero que te ayude.

Rahul Sharma
fuente
No es compatible con Ldispositivos previos .
Sakiboy
@Sakiboy Sí lo es, ya que estoy usando este código con un mínimo de API 17.
Rahul Sharma
No funciona con VectorDrawablestodos los dispositivos que ejecutan pre-L, solo digo. Tenga cuidado al usar esta respuesta, ya que hay API más seguras y precisas para usar.
Sakiboy
4

He diseñado una pequeña biblioteca para esto: textview-rich-drawable (también admite la definición del tamaño y el tinte de los dibujables compuestos).

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

Y la dependencia

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

ingrese la descripción de la imagen aquí

Oleksandr
fuente
3

Si está utilizando enlace, hay otra forma mágica de tener el mismo enfoque para usar vectores en un TextView. Envolviéndolos como:

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

Eso funcionará mágicamente, no he investigado lo que sucede detrás de escena, pero supongo que TextView está utilizando el getDrawablemétodo de AppCompatResourceso similar.

cesards
fuente
2

Basado en la respuesta de Behzad Bahmanyar , noté que no podía usar los atributos normales de Android para archivos PNG normales:

android:drawableTop
android:drawableBottom
etc

porque sería reemplazado por nulo en

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

si app:drawableTopCompatno se configuró, peroandroid:drawableTop (por ej.).

Aquí está la solución 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();
    }
}
Goran Horia Mihail
fuente
Esto debe ser aceptado respuesta. trabajar con archivos y atributos png normales drawableTop, drawableBottom. La respuesta aceptada no funciona con el archivo png y los atributos drawableTop, drawableBottom.
Bhargav Pandya
2

En el archivo build.gradle (aplicación)

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

uso (cuando enlace de datos)

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

O (normal)

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

Uso 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);
Margen
fuente
1

Para compatibilidad con versiones anteriores, use:

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

Estoy usando un adaptador de enlace para resolver este 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)
}

y también usar de esta manera en mi diseño

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

probablemente vectorDrawables.useSupportLibrary = true en la configuración predeterminada es necesario

Mahdi ZTD
fuente