Uso de elementos de diseño vectoriales de Android en el bloqueo previo de Lollipop

91

Estoy usando elementos de diseño vectoriales en Android antes de Lollipop y estas son algunas de mis bibliotecas y versiones de herramientas:

  • Estudio de Android: 2.0
  • Complemento de Android Gradle: 2.0.0
  • Herramientas de compilación: 23.0.2
  • Biblioteca de soporte de Android: 23.3.0

Agregué esta propiedad en mi nivel de aplicación Build.Gradle

android {  
  defaultConfig {  
    vectorDrawables.useSupportLibrary = true  
   }  
}

También vale la pena mencionar que utilizo un dibujable adicional como LayerDrawable (layer_list) como se indica en el Blog oficial de Android ( enlace aquí ) para configurar elementos de diseño para elementos de diseño vectoriales fuera deapp:srcCompat

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/search"/>
</level-list>

Encontrará elementos de diseño vectoriales que hacen referencia directamente fuera de la aplicación: srcCompat fallará antes de Lollipop. Sin embargo, AppCompat admite la carga de elementos de diseño vectoriales cuando se hace referencia a ellos en otro contenedor dibujable, como StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable y RotateDrawable. Al usar esta indirección , puede usar elementos de diseño vectoriales en casos como el atributo android: drawableLeft de TextView, que normalmente no podría admitir elementos de diseño vectoriales.

Cuando estoy usando app:srcCompattodo funciona bien, pero cuando uso:

android:background
android:drawableLeft
android:drawableRight
android:drawableTop
android:drawableBottom

en ImageView, ImageButton, TextViewo EditTextantes de la Piruleta, lanza una expection:

Caused by: android.content.res.Resources$NotFoundException: File res/drawable/search_toggle.xml from drawable resource ID #0x7f0200a9
Behzad Bahmanyar
fuente
Posible duplicado de la compatibilidad de vectores
Adam Hurwitz
Para ver cómo usar VectorDrawable con drawableLeft, drawableRight, drawableTop, drawableBottom, consulte esta respuesta
Behzad Bahmanyar
¿Puedes comprobar mi respuesta aquí? stackoverflow.com/a/40523623/2557258
Yazon2006
En mi caso, los diseños de vactor no estaban en el paquete correcto (vista de proyecto abierta) respuesta original aquí stackoverflow.com/a/35836318/2163045
murt

Respuestas:

102

ÚLTIMA ACTUALIZACIÓN - Jun / 2019

La biblioteca de soporte ha cambiado un poco desde la respuesta original. Ahora, incluso el complemento de Android para Gradle puede generar automáticamente el PNG en el momento de la compilación. Entonces, a continuación hay dos enfoques nuevos que deberían funcionar en estos días. Puedes encontrar más información aquí:

Generación PNG

Gradle puede crear automáticamente imágenes PNG a partir de sus activos en el momento de la compilación. Sin embargo, en este enfoque, no se admiten todos los elementos xml . Esta solución es conveniente porque no necesita cambiar nada en su código o en su build.gradle. Solo asegúrese de estar utilizando el complemento de Android 1.5.0 o superior y Android Studio 2.2 o superior .

Estoy usando esta solución en mi aplicación y funciona bien. No se necesita una bandera build.gradle adicional . No es necesario ningún truco. Si va a / build / generate / res / pngs / ... puede ver todos los PNG generados.

Entonces, si tiene algún ícono simple (ya que no todos los elementos xml son compatibles), esta solución puede funcionar para usted. Simplemente actualice su Android Studio y su complemento de Android para Gradle.

Biblioteca de soporte

Probablemente, esta es la solución que funcionará para usted. Si vino aquí, significa que su Android Studio no está generando los PNG automáticamente. Entonces, tu aplicación falla.

O tal vez, no desea que Android Studio genere ningún PNG.

A diferencia de la "generación Auto-PNG" que admite un subconjunto de elementos XML, esta solución admite todas las etiquetas xml. Por lo tanto, tiene soporte completo para su diseño vectorial.

Primero debe actualizar su build.gradle para admitirlo :

android {
  defaultConfig {
    // This flag will also prevents Android Studio from generating PNGs automatically
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
  // Use this for Support Library
  implementation 'com.android.support:appcompat-v7:23.2.0' // OR HIGHER

  // Use this for AndroidX
  implementation 'androidx.appcompat:appcompat:1.1.0' // OR HIGHER
}

Y luego, use en app:srcCompatlugar de android:srcmientras cargaVectorDrawables . No olvide esto.

Porque TextView, si está usando la androidxversión de la biblioteca de soporte, puede usar app:drawableLeftCompat(o derecha, arriba, abajo) en lugar deapp:drawableLeft

En caso de CheckBox/ RadioButton, use en app:buttonCompatlugar deandroid:button .

Si no está utilizando la androidxversión de la biblioteca de soporte y su minSdkVersiones 17o superior o está utilizando un botón, puede intentar configurar mediante programación a través de

Drawable icon = AppCompatResources.getDrawable(context, <drawable_id>);
textView.setCompoundDrawablesWithIntrinsicBounds(<leftIcon>,<topIcon>,<rightIcon>,<bottomIcon>);

ACTUALIZACIÓN - Jul / 2016

Reactivaron ese VectorDrawable en la
biblioteca de soporte de Android 23.4.0

Para los usuarios de AppCompat , hemos agregado una API opt-in para volver a habilitar el soporte Vector Drawables de los recursos (el comportamiento que se encuentra en 23.2) a través de AppCompatDelegate.setCompatVectorFromResourcesEnabled (verdadero) - tenga en cuenta que esto aún puede causar problemas con el uso de la memoria y problemas al actualizar las instancias de configuración, por lo que está deshabilitado por defecto

tal vez ,build.gradle configuración ahora esté obsoleta y solo necesite habilitarla en las actividades adecuadas (sin embargo, debe probarla).

Ahora, para habilitarlo, debe hacer:

public class MainActivity extends AppCompatActivity {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

    ...
}

Respuesta original - Abril / 2016

Creo que esto está sucediendo porque Support Vector estaba deshabilitado en la última versión de la biblioteca: 23.3.0

Según este POST :

Para los usuarios de AppCompat, hemos decidido eliminar la funcionalidad que le permite usar elementos de diseño vectoriales de los recursos en dispositivos anteriores a Lollipop debido a problemas encontrados en la implementación en la versión 23.2.0 / 23.2.1 (NÚMERO 205236) . El uso de la aplicación: srcCompat y setImageResource () continúa funcionando.

Si visita el problema ISSUE 205236 , parece que se habilitarán en el futuro, pero el problema de la memoria no se solucionará pronto:

En la próxima versión, agregué una API opt-in donde puede volver a habilitar el soporte de VectorDrawable que se eliminó. Sin embargo, viene con las mismas advertencias que antes (uso de memoria y problemas con la actualización de la configuración).

Tuve un problema similar. Entonces, en mi caso, revirtí todos los íconos que usan dibujables vectoriales de recursos a imágenes PNG nuevamente (ya que el problema de memoria seguirá sucediendo incluso después de que brinden una opción para habilitarlo nuevamente).

No estoy seguro de si esta es la mejor opción, pero en mi opinión soluciona todos los fallos.

W0rmH0le
fuente
1
Gracias @Guilherme P., pero ¿por qué no eliminó la vectorDrawables.useSupportLibrary = truepropiedad para volver a habilitar la generación de png en el momento de la compilación nuevamente?
Behzad Bahmanyar
1
Eso fue deshabilitado en la última versión v23.3.0 debido a problemas de memoria. De esta manera, no pueden generar png en tiempo de ejecución ... Por eso en el error logcat imprimen: vector de etiqueta desconocido (o algo así).
W0rmH0le
4
Aquí están las instrucciones de participación plus.google.com/+AndroidDevelopers/posts/B7QhFkWZ6YX . Desafortunadamente, VectorDrawables todavía no funciona en el dispositivo Pre-Lollipop. Estoy en la biblioteca de soporte 23.4.0 y he llamado tanto 'generateDensities = []' como 'vectorDrawables.useSupportLibrary = true' en defaultConfig {}.
Adam Hurwitz
1
@AdamHurwitz Actualicé la respuesta ... Parece que se habilitó de nuevo ... Sin embargo, debe habilitarlo de manera diferente ahora.
W0rmH0le
1
@juztcode Tienes razón. Debe usar 'androidx.appcompat: appcompat: 1.1.0'
W0rmH0le
63

Yo tuve el mismo problema. Pero haciendo mucho I + D obtuve la respuesta.

Para el uso de Imageview e ImageButton, app:srcCompat="@drawable/...." y para otras vistas como Button, Textview, en lugar de usar "drawableLeft/right..."en el XML, especifique los elementos de diseño mediante programación como:

button.setCompoundDrawablesWithIntrinsicBounds(AppCompatResources.getDrawable(mContext,R.drawable.ic_share_brown_18dp), null, null, null);

Y use "AppCompatResources" para obtener el elemento de diseño.

Shashank Kapsime
fuente
59

Para desarrollar las otras muy buenas respuestas , aquí hay un diagrama que puede ayudarlo. Es válido si tiene una biblioteca de soporte desde 23.4.0 hasta al menos 25.1.0.

Hoja de referencia dibujable

David Ferrand
fuente
1
en caso de que esté intentando establecer drawableLeft, envuélvalo dentro de un dibujable como se menciona aquí. medium.com/@chrisbanes/…
nizam.sp
Gracias este gráfico nos ayuda mucho.
silentsudo
39

La respuesta de Guillherme P es bastante impresionante. Solo para hacer una pequeña mejora, no necesita agregar esa línea en cada actividad, si la agregó una vez en la clase Aplicación, también funcionará.

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

RECUERDE: aún debe haber habilitado el uso de la biblioteca de soporte en gradle:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Además, asegúrese de estar utilizando una versión de la biblioteca de soporte superior a la v23.4, cuando Google volvió a agregar el soporte para Drawable Containers para VectorDrawables ( nota de la versión )

Actualizar

Y para cambios de código:

  1. Asegúrese de actualizar app:srcCompattodos los lugares que acepten el android:srcatributo (el IDE le advertirá si no es válido, como para la <bitmap>etiqueta).
  2. Para drawableLeft, drawableStart, drawableRight, drawableEndatributos utilizados en TextViewy puntos de vista similares, se tendrán que establecer mediante programación por ahora. Un ejemplo de configuración drawableStart:

    Drawable drawable = AppCompatResources.getDrawable(
            getContext(),
            R.drawable.your_vector_drawable);
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        textView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
    }
Benny
fuente
recuerde que debe tener activado el uso de la biblioteca de soporte para elementos de diseño vectoriales en gradle: vectorDrawables.useSupportLibrary = true
Benny
2
Sí. Lo sé. Pero es necesario un contenedor para que los elementos de diseño vectoriales funcionen como elementos de diseño para TexViews, por lo que esta respuesta está incompleta.
cesar el
1
Gran respuesta. Es particularmente bueno para aplicaciones con todas sus actividades extendidas desde una actividad base personalizada.
Hong
14

Yo tuve el mismo problema. Y arreglarlo quitando

vectorDrawables.useSupportLibrary = true

Mi versión de destino es 25 y la biblioteca de soporte es

 compile 'com.android.support:appcompat-v7:25.3.1'
Rajesh Nasit
fuente
1
esto funcionó para mí. Gracias. Acabo de eliminar esovectorDrawables.useSupportLibrary = true
Android Mediocre
Creo que esta no es la manera correcta de hacerlo, de cualquier manera, di mi voto a tu respuesta. !!
Harish Reddy
Gracias. t funciona para mi aplicación. Todos los elementos de diseño vectoriales siguen funcionando si se han eliminado. La aplicación usa com.android.support:appcompat-v7:28.0.0
Hong
10

VectorDrawables en pre-lollipop debería funcionar bien sin usar

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

Si desea usar VectorDrawables dentro de ImageViews, puede usar el atributo srcCompaty funcionará, pero dentro de Buttons o TextViews no lo hará , por lo que debe envolver el Drawable en un InsetDrawable o LayerDrawable. Hay otro truco que descubrí, si está utilizando el enlace de datos, puede hacer esto:

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 está sucediendo detrás de escena, pero supongo que TextView está usando el método getDrawable de AppCompatResources o similar.

cesar
fuente
¿Cómo configurar la imagen vectorial en el selector?
Tushar Gogna
después de configurar vectorDrawables.useSupportLibrary = true en gradle predeterminado y AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); en actividad en la creación Para evitar fallas con android: drawableleft en Textview , establezca drawble left en textview programáticamente para ejemplo: textview.setCompoundDrawablesWithIntrinsicBounds (R.drawable.movie, 0, 0, 0);
Afjalur Rahman Rana
7

Gran cantidad de I + D, finalmente obteniendo esta solución para fallas en dispositivos pre-piruleta.

Para Imageview

  • use la aplicación: srcCompat en lugar de android: src

Para TextView / EditText

  • Elimine drawableleft , drawableright .... y establezca desde el código java dibujable.

txtview.setCompoundDrawablesWithIntrinsicBounds (AppCompatResources.getDrawable (EventDetailSinglePage.this, R.drawable.ic_done_black_24_n), nulo, nulo, nulo);

Para Build.gradle

vectorDrawables.useSupportLibrary = true

Jatin Mandanka
fuente
1
Fue la solución única que funcionó en TextInputEditText.
heronsanches
1
Impresionante, esto se resuelve mi problema. Esta respuesta debería ser aceptada
DJtiwari
7

Uso de la forma más fácil:

app:drawableRightCompat ="@drawable/ic_mobilelogin"
app:drawableEndCompat="@drawable/ic_mobilelogin"
app:srcCompat="@drawable/ic_mobile"

y ... solo utilícelo app:**Compatpara compatibilidad. También agregue soporte en build.gradle(módulo)

android {
   defaultConfig {
       vectorDrawables.useSupportLibrary = true
   }
}
Hamed Jaliliani
fuente
app: drawableEndCompat y app: drawableRightCompat es prácticamente lo mismo si es en inglés
Hossam Hassan
5

Para cualquier persona que actualice a Android Gradle 3.0 y superior, no es necesario usarlo AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)o configurarlo vectorDrawables.useSupportLibrary = true(agregar esto causará problemas) y usarlo app:srcCompat, simplemente funciona.

Tómeme dos días para resolver esto, y no he encontrado ningún documento relacionado en los documentos de Google ...

Geng Jiawen
fuente
Interesante, estoy usando gradle 3.3.0 y esta solución funciona. Sin embargo, Android Studio todavía me dice que habilite set vectorDrawables.useSupportLibrary = true.
masterwok
2

Estoy usando VectorDrawables en dispositivos Pre-Lollipop y así es como lo hago: -

Paso 1: Pon esto en tu nivel de aplicación gradle.

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Paso 2:

Pon esto en tu clase de Aplicación y no olvides registrar tu clase de Aplicación en el archivo de manifiesto.

public class App extends Application {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
}

Paso 3:

Obtenga VectorDrawables usando,

imageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.my_vector_drawable));
Parag Kadam
fuente
2

Después de usar el siguiente código.

android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true  
                }
        }




public class App extends Application {
static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}}

Aún así, existe un problema de imágenes vectoriales porque los atributos siguientes son

DrawableEnd, DrawableStart, DrawableTop, DrawableBottom, Fondo

En este caso, siga lo siguiente, en lugar de hacer referencia a la imagen vectorial directamente, use la etiqueta de selector como un archivo de diseño intermedio.

Ejemplo:

ic_warranty_icon.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="17"
android:viewportHeight="24">

<path
    android:fillColor="#fff"
    android:pathData="M10.927,15.589l-1.549,0.355a7.47,7.47 0,0 1,-0.878 0.056c-4.136,0 -7.5,-3.364 -7.5,-7.5s3.364,-7.5 7.5,-7.5 7.5,3.364 7.5,7.5c0,3.286 -2.126,6.078 -5.073,7.089zM8.5,2a6.508,6.508 0,0 0,-6.5 6.5c0,3.583 2.917,6.5 6.5,6.5s6.5,-2.917 6.5,-6.5 -2.917,-6.5 -6.5,-6.5z" />

safe_ic_warranty_icon.xml

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

Su TextView / Layout.

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawableStart="@drawable/ic_warranty_icon"
       />


<LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/ic_warranty_icon"
       />
Rajesh Gr
fuente
Gracias !!! Para la propiedad de fondo, agregar un selector en el medio en lugar de usar directamente el vector de diseño funcionó para la api anterior a lollipop (19).
Ankur
en mi caso, esto todavía no funciona para API (16), incluso envolviendo conselector
mochadwi
1

Probamos 3 cosas

vectorDrawables.useSupportLibrary = true

Configuración de setCompatVectorFromResourcesEnabled en la clase de aplicación

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Y use app:srcCompat

Pero incluso después de eso, estaba fallando

Resources$NotFoundException: File res/drawable/$my_icon__0.xml from color state list resource ID #0x7f080008

luego descubrimos que nuestro SVG tenía una etiqueta de degradado. La conversión de la etiqueta de degradado en rutas individuales para la API inferior <= 23 y el uso de la misma API de SVG> = 24 funcionó.

Obtuve ayuda de esta respuesta https://stackoverflow.com/a/47783962/2171513

Aalap
fuente
No sé por qué nadie votó a favor de esto, pero esta podría ser la solución a mi problema. Gracias
DevMike01
0

Simplemente superponga el vector dibujable a la lista de estados, luego el problema se resolverá

Por ejemplo, tiene una imagen vectorial de flecha hacia atrás:

ic_back_arrow.xml

sí, debe superponerlo a la lista de capas xml (ic_back_arrow_vector_vector.xml):

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_back_arrow"/>
</layer-list>

Porque la lógica:

vectorDrawables.useSupportLibrary = true

y

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

no le ayudará en algunos dispositivos de China y dispositivos Samsung más antiguos. Si no los superpone, fallará.

mr.boyfox
fuente
0

Estuve luchando con esto durante horas.

Intenté todo lo que me dijeron estas respuestas, pero mi aplicación no dejó de fallar. Eliminé esta línea: app:srcCompat="@drawable/keyboard"y mi aplicación dejó de fallar. y luego, cuando agregué esto mismo, comenzó a fallar nuevamente. Así que decidí abrir ese archivo y vi un error en la primera línea que decía

"El 'Teclado' dibujable no tiene ninguna declaración en la carpeta dibujable base; esto puede provocar bloqueos.

Hice clic derecho en el archivo y en "Mostrar en el explorador" y no estaba en la carpeta dibujable sino en el directorio drawable-v24. Así que lo copié y pegué en el directorio dibujable y finalmente me deshice de los bloqueos.

Fahad Maqsood Qazi
fuente
-2

La sugerencia de Guilherme P no funcionó para mí. Seguí adelante y tomé la decisión de usar png donde necesito hacer cosas fuera de la aplicación: srcCompat, es decir, drawableLeft, drawableRight, etc. Este fue un cambio bastante fácil de hacer y no tiene los posibles problemas de memoria AppCompatDelegate.setCompatVectorFromResourcesEnabled ( cierto); introduce.

Ryan Newsom
fuente
-3

Una alternativa a la respuesta de Benny es crear una Activitysuperclase:

public abstract class VectorDrawableActivity extends AppCompatActivity {
  static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
  }

  //...
}

Ahora extienda en VectorDrawableActivitylugar de AppCompatActivity.

Aprendiz de código
fuente
@cesards ¿Por qué no?
Code-Apprentice