Cómo centrar el dibujo vectorial en la lista de capas sin escalar

102

Estoy intentando usar un VectorDrawablein a LayerListsin escalar el vector. Por ejemplo:

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
    <item android:gravity="center" android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

La ic_check_white_48dpidentificación dibujable definida como:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#FFFFFFFF"
        android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

El efecto deseado es que el icono de verificación esté centrado en la capa dibujable, sin escalar. El problema es que la lista de capas anterior hace que el icono de verificación se escale para ajustarse al tamaño de la capa.

I puedo producir el efecto deseado si se sustituye la dibujable vector con PNGs para cada densidad y modificar la lista de capas como tal:

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
    <item>
        <bitmap android:gravity="center" android:src="@drawable/ic_check_white_48dp"/>
    </item>
</layer-list>

¿Hay alguna forma de que pueda hacer esto usando un VectorDrawable?

Ashughes
fuente
11
Parece que esto puede ser simplemente un error en API 21/22. Acabo de probar en un dispositivo API 23 y el vector dibujable estaba correctamente centrado.
Ashughes
1
Debe responder su propia pregunta y aceptarla. De esa manera es más visible y la pregunta no aparece sin respuesta.
Marcin Koziński
1
No he respondido a mi pregunta porque todavía no tengo una respuesta sobre qué hacer en API 21/22. Mi solución temporal fue usar PNG en lugar de vectores. Sin embargo, con la esperanza de encontrar una manera de hacer que los vectores funcionen.
ashughes
1
Abrí un problema aquí: code.google.com/p/android/issues/detail?id=219600
toobsco42
Esto ya está arreglado en API 23, por lo que supongo que su informe de error se marcará como arreglado.
Ashughes

Respuestas:

29

Me encontré con el mismo problema al intentar centrar los elementos de diseño de los vectores en una lista en capas.

Tengo una solución alternativa, no es exactamente lo mismo pero funciona, necesita establecer un tamaño para todo el elemento de dibujo y agregar relleno al elemento vectorial:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <size android:height="120dp" android:width="120dp"/>
            <solid android:color="@color/grid_item_activated"/>
        </shape>
    </item>
    <item android:top="24dp"
          android:bottom="24dp"
          android:left="24dp"
          android:right="24dp"
          android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

El tamaño de la forma anterior establece el tamaño de todo el elemento dibujable, 120 dp en este ejemplo, el relleno del segundo elemento, 24 dp en este ejemplo, centra la imagen vectorial.

No es lo mismo que usar el, gravity="center"pero su forma de trabajo de usar vectores en API 21 y 22.

Nicolas Tyler
fuente
2
Esto parece que requeriría que conozca el tamaño exacto del dibujable (para establecer el tamaño de la forma), en lugar de dejar que llene todo el espacio en el que está configurado con el cheque dibujable centrado dentro de él.
Ashughes
1
es posible no conocer el tamaño pero no puede cambiar el relleno con este método, puede colocar los elementos de diseño uno encima del otro en las vistas de imágenes. Como dije anteriormente, no existe una solución perfecta para una gravity="center"API 21 y 22.
Nicolas Tyler
No funciona cuando se usa con windowBackground. Los tamaños explícitos no hacen nada en este caso. Y tampoco funciona si pongo la lista de capas dentro de otra lista de capas.
Vsevolod Ganin
19

He estado luchando con el mismo problema. La única forma que encontré para solucionar esto y evitar que el dibujable se ampliara fue establecer el tamaño del dibujable y usar la gravedad para alinearlo:

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
     <item
        android:gravity="center"
        android:width="48dp"
        android:height="48dp"
        android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

¡Espero eso ayude!

Felipe Duarte
fuente
34
Esto no ayuda en API 21-22, porque el widthatributo no está disponible en esos niveles de API. En API 23, estos no son necesarios, porque el error se corrigió y el dibujable ya no se estira.
WonderCsabo
3
Esto no funciona correctamente para API 27, la imagen se ha
ampliado
8

Solución editada que hará que su SplashScreen se vea genial en todas las API, incluidas API21 a API23

En primer lugar, lea este artículo y siga la BUENA forma de crear una pantalla de bienvenida.

Si su logotipo está distorsionado o no encaja y solo está apuntando a APIs24 +, simplemente puede reducir su vector dibujable directamente en su archivo xml de la siguiente manera:

<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="640"
android:viewportHeight="640"
android:width="240dp"
android:height="240dp">
<path
    android:pathData="M320.96 55.9L477.14 345L161.67 345L320.96 55.9Z"
    android:strokeColor="#292929"
    android:strokeWidth="24" />
</vector>

en el código anterior, estoy cambiando la escala de un elemento de dibujo que dibujé en un lienzo de 640x640 para que sea 240x240. luego lo puse en mi pantalla de presentación dibujable así y funciona muy bien:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"
android:paddingBottom="20dp" android:paddingRight="20dp" android:paddingLeft="20dp" android:paddingTop="20dp">

<!-- The background color, preferably the same as your normal theme -->
<item>
    <shape>
        <size android:height="120dp" android:width="120dp"/>
        <solid android:color="@android:color/white"/>
    </shape>
</item>

<!-- Your product logo - 144dp color version of your app icon -->
<item
    android:drawable="@drawable/logo_vect"
    android:gravity="center">

</item>
</layer-list>

mi código en realidad solo dibuja el triángulo en la imagen en la parte inferior, pero aquí puede ver lo que puede lograr con esto. La resolución es finalmente excelente en comparación con los bordes pixelados que obtenía al usar mapa de bits. así que use un dibujo vectorial por todos los medios (hay un sitio llamado vectr que usé para crear el mío sin la molestia de descargar software especializado).

EDITAR para que funcione también en API21-22-23

Si bien la solución anterior funciona para dispositivos que ejecutan API24 +, me decepcionó mucho después de instalar mi aplicación en un dispositivo que ejecuta API22. Me di cuenta de que la pantalla de bienvenida intentaba volver a llenar toda la vista y parecía una mierda. Después de arrancarme las cejas durante medio día, finalmente forcé brutalmente una solución por pura fuerza de voluntad.

necesita crear un segundo archivo llamado exactamente como el xml de la pantalla de presentación (digamos splash_screen.xml) y colocarlo en 2 carpetas llamadas drawable-v22 y drawable-v21 que creará en la carpeta res / (para poder verlas usted tienes que cambiar la vista de tu proyecto de Android a Project). Esto sirve para decirle a su teléfono que redirija a los archivos ubicados en esas carpetas siempre que el dispositivo relevante ejecute una API correspondiente al sufijo -vXX en la carpeta dibujable, vea este enlace . coloque el siguiente código en la lista de capas del archivo splash_screen.xml que crea en estas carpetas:

<item>
<shape>
    <size android:height="120dp" android:width="120dp"/>
    <solid android:color="@android:color/white"/>
</shape>
</item>

<!-- Your product logo - 144dp color version of your app icon -->
<item android:gravity="center">
    <bitmap android:gravity="center"
        android:src="logo_vect"/>

</item>

así es como se ven las carpetas

Por alguna razón, para estas API, debe envolver su elemento de dibujo en un mapa de bits para que funcione y el resultado final se vea igual. El problema es que debe usar el enfoque con las carpetas extraíbles adicionales, ya que la segunda versión del archivo splash_screen.xml hará que su pantalla de presentación no se muestre en absoluto en los dispositivos que ejecutan API superiores a 23. También es posible que deba colocar la primera versión de splash_screen.xml en drawable-v24 ya que Android tiene por defecto la carpeta drawable-vXX más cercana que puede encontrar para los recursos.

mi pantalla de bienvenida

quealegriamasalegre
fuente
4

Actualmente estoy trabajando en una pantalla de presentación con un vector dibujable centrado tanto horizontal como verticalmente. Esto es lo que obtuve en el nivel de API 25:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">

<!-- background color, same as theme -->
<item android:drawable="@android:color/white"/>

<!-- app logo -->

<item
    android:drawable="@drawable/my_app_logo"
    android:gravity="center_horizontal|center_vertical"
    android:width="200dp"
    android:height="200dp"
    />
</layer-list>

Si desea ajustar la dimensión del elemento de diseño vectorial, modifique android:widthyandroid:height atributos anteriores, no necesariamente modifique el elemento de diseño original.

Además, mi experiencia es NO poner el vector dibujable en una etiqueta de mapa de bits, lo que nunca me funciona. El mapa de bits es para archivos de formato .png, .jpg y .gif, no para dibujables vectoriales.

Referencia

https://developer.android.com/guide/topics/resources/drawable-resource#LayerList

https://developer.android.com/guide/topics/resources/more-resources.html#Dimension

Wenhe Qi
fuente
1
Buena captura sobre los elementos de diseño vectoriales que necesitan estar dentro de una etiqueta <item> en lugar de una etiqueta <bitmap>.
FrostRocket