redondo - ¿Cómo establecer el tamaño del vector dibujable dentro de un botón en Android?
imagebutton android studio (1)
Las herramientas Android Studio Vector Assets convierten vectores dibujables a PNG-s para dispositivos anteriores a Lollipop, pero obtengo PNG-s de mala calidad como se puede ver aquí:
Además, se supone que el color sólido de fondo del botón es este verde claro que se ve a la izquierda, pero el dibujo extraíble lo sobrescribe:
<item android:state_checked="true"
android:drawable="@drawable/show">
<shape android:shape="rectangle">
<corners android:bottomRightRadius="8dp"/>
<solid android:color="@color/waveComponentGreen"/>
</shape>
</item>
<item android:state_checked="false"
android:drawable="@drawable/hide">
<shape android:shape="rectangle">
<corners android:bottomRightRadius="8dp"/>
<solid android:color="@color/waveComponentGreen"/>
</shape>
</item>
El xml para el dibujable es (el predeterminado de los iconos de material):
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
También quería hacer que el icono pareciera un poco más pequeño ajustando los valores y me di cuenta de que al aumentar las dimensiones de la ventana disminuyo el ícono, pero no estoy seguro de entender por qué.
Entonces, ¿cómo hago que el icono y el PNG generado parezcan más pequeños, menos borrosos y con el color de fondo establecido en el archivo de recursos? Gracias.
EDITAR : logré obtener el fondo de color sólido con el icono combinándolos en un archivo xml separado con listas de capas:
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<corners android:bottomRightRadius="10dp"/>
<solid android:color="@color/waveComponentGreen"/>
</shape>
</item>
<item android:drawable="@drawable/show"
android:top="10dp"
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
/>
El resultado es:
Logré reducir el desenfoque al aumentar el ancho y la altura del vector dibujable. Sin embargo, sin las etiquetas android:top|bottom|left|right
, el dibujable se extiende por toda el área del botón. El segundo botón no necesita tener un fondo de color sólido, así que no estoy usando las etiquetas de la lista de capas => no hay forma de establecer un margen top|bottom|left|right
para el dibujable.
Si reduzco el tamaño del botón, lo que estoy haciendo es reducir el área en la que se puede hacer clic.
Mi pregunta actualizada es cómo configurar el tamaño del vector dibujable dentro de un botón / botón de alternar / botón de radio sin reducir el tamaño del botón.
ACTUALIZAR
No pude encontrar una forma de cambiar el tamaño del vector dibujable en dispositivos pre API 21. Así que, en cambio, hice los botones más pequeños y aumenté el área táctil de cada botón.
El enfoque correcto para escalar cualquier dibujable sería usar vectorDrawable.setBounds(left,top,right,bottom)
, pero desafortunadamente eso no funciona para los vectores dibujables (¿por qué Google?).
Así que, como solución alternativa, cargo mis vectores arrastrables, los convierto en mapa de bits dibujable y eso nos permitirá usar el método setBounds
en el mapa de bits dibujable. Tenga en cuenta que está escalando mapas de bits aquí, por lo que puede perder algo de nitidez en la imagen. Principalmente uso esos métodos cuando necesito usar mi dibujable como un compuesto compuesto de una vista de texto o un botón, por ejemplo.
Terminé escribiendo una clase de ayuda que cargará un vector dibujable establecer un tinte para él y devolver un mapa de bits dibujable que realmente puede escalar y matizar como desee. Lo he probado para niveles API de 19 hasta 23, y funciona.
No olvides utilizar vectorDrawables.useSupportLibrary = true
en tu build.gradle .
public class VectorDrawableUtils {
/**
* Gets a Bitmap from provided Vector Drawable image
*
* @param vd VectorDrawable
* @return Bitmap
*/
public static Optional<Bitmap> createBitmapFromVectorDrawable(final @NonNull Drawable vd) {
try {
Bitmap bitmap;
bitmap = Bitmap.createBitmap(vd.getIntrinsicWidth(), vd.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vd.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vd.draw(canvas);
return Optional.of(bitmap);
} catch (OutOfMemoryError e) {
Injector.getDependency(getContext(), IEventTracker.class).logHandledException(e);
return Optional.empty();
}
}
/**
* Loads vector drawable and apply tint color on it.
*/
public static Drawable loadVectorDrawableWithTintColor(final @DrawableRes int vdRes,
final @ColorRes int clrRes,final Context context) {
Drawable drawable = ContextCompat.getDrawable(context, vdRes);
DrawableCompat.setTint(drawable, getContext().getResources().getColor(clrRes));
return drawable;
}
/**
* Converts given vector drawable to Bitmap drawable
*/
public static BitmapDrawable convertVectorDrawableToBitmapDrawable(final @NonNull Drawable vd) {
//it is safe to create empty bitmap drawable from null source
return new BitmapDrawable(createBitmapFromVectorDrawable(vd).get());
}
/**
* Loads vector drawable , aplys tint on it and returns a wrapped bitmap drawable.
* Bitmap drawable can be resized using setBounds method (unlike the VectorDrawable)
* @param context Requires view context !
*/
public static Drawable loadVectorDrawableWithTint(
final @DrawableRes int vectorDrawableRes, final @ColorRes int colorRes,final Context context) {
Drawable vd = VectorDrawableUtils.loadVectorDrawableWithTintColor(vectorDrawableRes,
colorRes, context);
final BitmapDrawable bitmapDrawable = VectorDrawableUtils.convertVectorDrawableToBitmapDrawable(vd);
ColorStateList tint = ContextCompat.getColorStateList(context,colorRes);
final Drawable wrappedDrawable = DrawableCompat.wrap(bitmapDrawable);
DrawableCompat.setTintList(wrappedDrawable,tint);
return wrappedDrawable;
}
}
Ahora utilizaría esta clase de ayuda de esta manera:
Drawable bd = VectorDrawableUtils.loadVectorDrawableWithTint(
R.drawable.ic_dropdown, R.color.black,getContext());
bd.setBounds(0, 0, textView.getMeasuredHeight(), textView.getMeasuredHeight());
textView.setCompoundDrawablesWithIntrinsicBounds(null, null, bd, null);
¡Es importante usar un Contexto de una Vista o Actividad, no el contexto de la Aplicación! Espero que solucione su problema o ayude a alguien más. Y si alguien tiene una solución mejor y más limpia, estoy interesado en saberlo también.