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

Cuando uso activos VectorDrawable en una vista de texto o imagen, obtengo un error de ejecución cuando uso “android: DrawableRight” / “android: DrawableEnd” / “android: DrawableStart” / “android: DrawableLeft”.

La aplicación comstackrá 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 lockings como este.

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

(Sospecho que es una falla de la biblioteca de soporte para 23.2)

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

Aquí está mi diseño

     

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 sin modificar del sitio de diseño de materiales de Google.

     

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

 03-02 07:56:08.808 13863-13863/? E/AndroidRuntime: FATAL EXCEPTION: main 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) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) 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) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023) 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) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) 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.(TextView.java:622) at android.support.v7.widget.AppCompatTextView.(AppCompatTextView.java:60) at android.support.v7.widget.AppCompatTextView.(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) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023) 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) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) 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.(TextView.java:622) at android.support.v7.widget.AppCompatTextView.(AppCompatTextView.java:60) at android.support.v7.widget.AppCompatTextView.(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) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023) 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) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) 

Como parece que Google no va a hacer nada al respecto pronto, 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” :

             
  2. A continuación, 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:

      app:drawableEndCompat="@drawable/your_vector_drawable"  app:drawableTopCompat="@drawable/your_vector_drawable"  app:drawableBottomCompat="@drawable/your_vector_drawable"  /> 
    • Puedes hacer algo similar con Button , EditText y RadioButton porque derivaron de TextView

Espero que esto ayude 🙂

Esta solución ya no es correcta. Desde la versión 23.3.0 los vectores arrastrables solo se pueden cargar a través de la aplicación: srcCompat o setImageResource ()

Intenta envolver tu dibujo vectorial en lista de capas o selector:

  

ic_accessible_white_wrapped.xml:

    

La mejor manera que encontré:

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

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

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

Hoja de trucos de VectorDrawable

Ninguna de las otras respuestas funcionó, así es como he agregado un VectorDrawable a un TextView , debe usar VectorDrawableCompat.create() cuando se trata de VectorDrawables debajo de 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!

Desde Google: a partir de Android Support Library 23.3.0, los vectores arrastrables 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

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

Solo escribe

  

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

       

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 utilizar vectores arrastrables antes de Lollipop, debe habilitar los vectores arrastrables usando

vectorDrawables.useSupportLibrary = true

Entonces tu build.gradle necesita 2 nuevos comandos:

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

gracias a rkmax por el comentario

Revisé todas las respuestas y utilicé el último estudio de Android 3.0.1 y la biblioteca de compatibilidad de aplicaciones 26.1.0. Puedo asegurar que esto funciona bien.

En el archivo build.gradle (app)

 android { compileSdkVersion 26 defaultConfig { vectorDrawables.useSupportLibrary = true } } dependencies { implementation 'com.android.support:appcompat-v7:26.1.0' } 

Y en la actividad que extiende AppcompatActivity incluya estos métodos externos, es decir, un bloque estático

 static { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); } 

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

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

Textview en xml

    

account_drawableleft_selector.xml

      

Estoy muy retrasado para responder a esta pregunta ya que llegué tarde con este problema. Tuve el mismo problema con svg / vector drawables con TextView. En lugar de hacer tu propio dibujante 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.

Si está utilizando el 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 las escenas, pero supongo que TextView está usando el método getDrawable de AppCompatResources o similar.

Diseñé una pequeña biblioteca para esto, textview-rich-drawable (también admite definir el tamaño y el tinte de los compuestos dibujables).

  

Y la dependencia

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

enter image description here

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

uso (cuando se vinculan datos)

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

O (Normal)

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

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 la app:drawableTopCompat no estaba configurada, pero android:drawableTop era (por ejemplo).

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