¿Cómo puedo encoger el dibujo de un botón?

87

¿Cómo puedo hacer que el dibujo de un botón sea más pequeño? El icono es demasiado grande, en realidad más alto que el botón. Este es el código que estoy usando:

    <Button
    android:background="@drawable/red_button"
    android:drawableLeft="@drawable/s_vit"
    android:id="@+id/ButtonTest"
    android:gravity="left|center_vertical" 
    android:text="S-SERIES CALCULATOR"
    android:textColor="@android:color/white"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:layout_marginLeft="25dp"
    android:layout_marginRight="25dp"
    android:drawablePadding="10dp">
    </Button>

La parte superior es como debería verse, la inferior como se ve ahora.

La parte superior es como debería verse, la inferior como se ve ahora.

Intenté esto pero no se muestra ninguna imagen. :-(

    Resources res = getResources();
    ScaleDrawable sd = new ScaleDrawable(res.getDrawable(R.drawable.s_vit), 0, 10f, 10f);
    Button btn = (Button) findViewById(R.id.ButtonTest);
    btn.setCompoundDrawables(sd.getDrawable(), null, null, null);
Reto
fuente
Sería mejor si carga una imagen de lo que está obteniendo y lo que está tratando de hacer. Gracias.
Lalit Poptani
Puede definir su botón personalizado para definir el tamaño de los elementos de diseño. Vea mi respuesta aquí stackoverflow.com/a/31916731/2308720
Oleksandr
Sé que esto es de 2011 ... pero en realidad prefiero el aspecto del botón con la cámara saliendo de los límites del botón; lo habría dejado como estaba ... solo digo :)
killercowuk

Respuestas:

70

Debe usar un ImageButton y especificar la imagen en android:src, y establecerla android:scaletypeenfitXY


Configuración de dibujable escalado en código

Drawable drawable = getResources().getDrawable(R.drawable.s_vit);
drawable.setBounds(0, 0, (int)(drawable.getIntrinsicWidth()*0.5), 
                         (int)(drawable.getIntrinsicHeight()*0.5));
ScaleDrawable sd = new ScaleDrawable(drawable, 0, scaleWidth, scaleHeight);
Button btn = findViewbyId(R.id.yourbtnID);
btn.setCompoundDrawables(sd.getDrawable(), null, null, null); //set drawableLeft for example
Ronnie
fuente
Si configura el elemento de diseño en el código, puede cambiar su tamaño en función de la altura del botón y luego configurarlo.
Ronnie
¡Ahora se muestra la imagen pero no cambia de tamaño! Probé valores entre 0.1f y 10f. ¿Alguna idea? Gracias por su ayuda ...
Reto
Prueba estodrawable.setBounds(0, 0, drawable.getIntrinsicWidth()*0.5, drawable.getIntrinsicHeight()*0.5);
Ronnie
Si esto cambia el tamaño del dibujable, entonces puede eliminar la parte del dibujable a escala y usar el dibujable directamente.
Ronnie
2
¿Se supone que debemos establecer nuestros propios valores para scaleWidth y scaleHeight? ¿Son simplemente descriptivos?
SametSahin
89

Encontré una solución XML muy simple y efectiva que no requiere ImageButton

Haga un archivo dibujable para su imagen como se muestra a continuación y utilícelo para android:drawableLeft

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

    <item
    android:id="@+id/half_overlay"
    android:drawable="@drawable/myDrawable"
    android:width="40dp"
    android:height="40dp"
    />

</layer-list>

Puede establecer el tamaño de la imagen con android:widthy android:heightpropiedades.

De esta manera, al menos podría obtener el mismo tamaño para diferentes pantallas.

El inconveniente es que no es exactamente como fitXY, que escalaría el ancho de la imagen para ajustarse a X y escalaría la altura de la imagen en consecuencia.

compañero
fuente
9
Esta debería ser la respuesta aceptada. Si uno no quiere un ImageButton (por ejemplo, porque quiere texto, etc.), esta respuesta permite imágenes de tamaño dentro de un botón con texto más código cero.
Acero reciclado
3
Hice un nuevo dibujo como este y luego android:drawableTopagregué el nuevo dibujo. No importa qué valores para el ancho / alto establezca, me muestra el predeterminado.
driftking9987
9
No parece funcionar para las versiones de Android inferiores a Lollipop.
Jyotman Singh
32
alto, ancho solo funciona en API nivel 23 y superior. No se admite al revés.
Palak Darji
Estoy de acuerdo, esta es, con mucho, la mejor solución
Senzo Malinga
10

Los botones no cambian el tamaño de sus imágenes internas.

Mi solución no requiere manipulación de código.

Utiliza un diseño con TextView e ImageView.

El fondo del diseño debe tener el dibujo 3d rojo.

Es posible que deba definir el atributo xml android: scaleType .

Ejemplo:

<LinearLayout
    android:id="@+id/list_item"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:padding="2dp" >

    <ImageView
        android:layout_width="50dp"
        android:layout_height="fill_parent"
        android:src="@drawable/camera" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:lines="1"
        android:gravity="center_vertical"
        android:text="Hello - primary" />

</LinearLayout>

Por cierto:

  1. Contar con iconos de diferentes resoluciones puede resultar en una IU no predecible (el icono es demasiado grande o demasiado pequeño)
  2. El texto en la vista de texto (incluidos los botones) no llena el componente. Este es un problema de Android y no sé cómo solucionarlo.
  3. Puede usarlo como una inclusión.

Buena suerte

AlikElzin-kilaka
fuente
RE: TextViews, si quiero que la vista sea lo más pequeña posible, configuro el relleno en cero. De lo contrario, parece tener un relleno predeterminado.
William T. Mallard
6

Usa un ScaleDrawable como Abhinav sugirió .

El problema es que el dibujable no se muestra entonces, es una especie de error en ScaleDrawables. deberá cambiar el "nivel" mediante programación. Esto debería funcionar para todos los botones:

// Fix level of existing drawables
Drawable[] drawables = myButton.getCompoundDrawables();
for (Drawable d : drawables) if (d != null && d instanceof ScaleDrawable) d.setLevel(1);
myButton.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);
zeh
fuente
Agradable. ¡Creo que podría estar usando esto en un futuro cercano!
Abhinav
@zeh, ahora descubrí que funciona si ejecuta el código anterior antes de setContentView; de lo contrario, no funciona. Podría ser mejor si agrega esto a su publicación.
Buddy
Por alguna razón, mi solución anterior no funciona en todas las versiones de Android.
Buddy
6

Mi DiplayScaleHelper, que funciona perfectamente:

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ScaleDrawable;
import android.widget.Button;

public class DisplayHelper {

  public static void scaleButtonDrawables(Button btn, double fitFactor) {
        Drawable[] drawables = btn.getCompoundDrawables();

        for (int i = 0; i < drawables.length; i++) {
            if (drawables[i] != null) {
                if (drawables[i] instanceof ScaleDrawable) {
                    drawables[i].setLevel(1);
                }
                drawables[i].setBounds(0, 0, (int) (drawables[i].getIntrinsicWidth() * fitFactor),
                    (int) (drawables[i].getIntrinsicHeight() * fitFactor));
                ScaleDrawable sd = new ScaleDrawable(drawables[i], 0, drawables[i].getIntrinsicWidth(), drawables[i].getIntrinsicHeight());
                if(i == 0) {
                    btn.setCompoundDrawables(sd.getDrawable(), drawables[1], drawables[2], drawables[3]);
                } else if(i == 1) {
                    btn.setCompoundDrawables(drawables[0], sd.getDrawable(), drawables[2], drawables[3]);
                } else if(i == 2) {
                    btn.setCompoundDrawables(drawables[0], drawables[1], sd.getDrawable(), drawables[3]);
                } else {
                    btn.setCompoundDrawables(drawables[0], drawables[1], drawables[2], sd.getDrawable());
                }
            }
        }
    }
}
Владимир Фишер
fuente
4

Puede recurrir setBoundsa los elementos de diseño "compuestos" para modificar el tamaño de la imagen.

Pruebe este código para ajustar automáticamente el tamaño del elemento de diseño de su botón:

DroidUtils.scaleButtonDrawables((Button) findViewById(R.id.ButtonTest), 1.0);

definido por esta función:

public final class DroidUtils {

    /** scale the Drawables of a button to "fit"
     *  For left and right drawables: height is scaled 
     *  eg. with fitFactor 1 the image has max. the height of the button.
     *  For top and bottom drawables: width is scaled: 
     *  With fitFactor 0.9 the image has max. 90% of the width of the button 
     *  */
    public static void scaleButtonDrawables(Button btn, double fitFactor) {
        Drawable[] drawables = btn.getCompoundDrawables();

        for (int i = 0; i < drawables.length; i++) {
            if (drawables[i] != null) {
                int imgWidth = drawables[i].getIntrinsicWidth();
                int imgHeight = drawables[i].getIntrinsicHeight();
                if ((imgHeight > 0) && (imgWidth > 0)) {    //might be -1
                    float scale;
                    if ((i == 0) || (i == 2)) { //left or right -> scale height
                        scale = (float) (btn.getHeight() * fitFactor) / imgHeight;
                    } else { //top or bottom -> scale width
                        scale = (float) (btn.getWidth() * fitFactor) / imgWidth;                    
                    }
                    if (scale < 1.0) {
                        Rect rect = drawables[i].getBounds();
                        int newWidth = (int)(imgWidth * scale);
                        int newHeight = (int)(imgHeight * scale);
                        rect.left = rect.left + (int)(0.5 * (imgWidth - newWidth)); 
                        rect.top = rect.top + (int)(0.5 * (imgHeight - newHeight));
                        rect.right = rect.left + newWidth;
                        rect.bottom = rect.top + newHeight;
                        drawables[i].setBounds(rect);
                    }
                }
            }
        }
    }
}

Tenga en cuenta que es posible que esto no se llame en onCreate()una actividad, porque la altura y el ancho del botón no están (todavía) disponibles allí. Llame a esto onWindowFocusChanged()o use esta solución para llamar a la función.

Editado:

La primera encarnación de esta función no funcionó correctamente. Usó el código userSeven7s para escalar la imagen, pero regresar ScaleDrawable.getDrawable() no parece funcionar (tampoco regresaScaleDrawable ) para mí.

El código modificado se utiliza setBoundspara proporcionar los límites de la imagen. Android encaja la imagen en estos límites.

yonojoy
fuente
Gracias por haber dicho que no lo llame onCreate().
Binarian
1

Lo estoy haciendo como se muestra a continuación. Esto crea una imagen de tamaño 100x100 en el botón independiente de la imagen de entrada.

drawable.bounds = Rect(0,0,100,100)
button.setCompoundDrawables(drawable, null, null, null)

Sin usar ScaleDrawableninguno. No usar button.setCompoundDrawablesRelativeWithIntrinsicBounds()resolvió mi problema, ya que parece usar límites intrínsecos (tamaño de la imagen de origen) en lugar de los límites que acaba de establecer.

LP
fuente
0

Puede utilizar elementos de diseño de diferentes tamaños que se utilizan con diferentes densidades / tamaños de pantalla, etc. para que su imagen se vea bien en todos los dispositivos.

Vea aquí: http://developer.android.com/guide/practices/screens_support.html#support

HXCaine
fuente
Utilizo la misma imagen en diferentes lugares. Es por eso que no puedo cambiar su tamaño, debería mostrarse en el tamaño que quiero.
Reto
0

¿Intentaste envolver tu imagen en un ScaleDrawable y luego usarlo en tu botón?

Abhinav
fuente
2
Intenté esto, sin embargo, mi ScaleDrawable no se muestra. :-( Incluso no en un ImageView. Tomé el código de muestra y simplemente reemplacé el dibujable. ¿Alguna idea de por qué esto no funciona?
Reto
Yo tuve el mismo problema. ScaleDrawablesería perfecto, pero simplemente no funciona. Parece tener algo que ver con los "niveles". Más información aquí (y algunas soluciones que no son perfectas): stackoverflow.com/questions/5507539/…
zeh
(editar) lo arregló con un código genérico! Solución aquí que aún le permite usar ScaleDrawables: stackoverflow.com/a/13706836/439026
zeh
0

Aquí la función que creé para escalar elementos de diseño vectoriales. Lo usé para configurar TextView compuesto dibujable.

/**
 * Used to load vector drawable and set it's size to intrinsic values
 *
 * @param context Reference to {@link Context}
 * @param resId   Vector image resource id
 * @param tint    If not 0 - colour resource to tint the drawable with.
 * @param newWidth If not 0 then set the drawable's width to this value and scale 
 *                 height accordingly.
 * @return On success a reference to a vector drawable
 */
@Nullable
public static Drawable getVectorDrawable(@NonNull Context context,
                                         @DrawableRes int resId,
                                         @ColorRes int tint,
                                         float newWidth)
{
    VectorDrawableCompat drawableCompat =
            VectorDrawableCompat.create(context.getResources(), resId, context.getTheme());
    if (drawableCompat != null)
    {
        if (tint != 0)
        {
            drawableCompat.setTint(ResourcesCompat.getColor(context.getResources(), tint, context.getTheme()));
        }

        drawableCompat.setBounds(0, 0, drawableCompat.getIntrinsicWidth(), drawableCompat.getIntrinsicHeight());

        if (newWidth != 0.0)
        {
            float scale = newWidth / drawableCompat.getIntrinsicWidth();
            float height = scale * drawableCompat.getIntrinsicHeight();
            ScaleDrawable scaledDrawable = new ScaleDrawable(drawableCompat, Gravity.CENTER, 1.0f, 1.0f);
            scaledDrawable.setBounds(0,0, (int) newWidth, (int) height);
            scaledDrawable.setLevel(10000);
            return scaledDrawable;
        }
    }
    return drawableCompat;
}
zmicer
fuente
0
  • Con la función "IMPORTACIÓN POR LOTES DIBUJABLE", puede importar un tamaño personalizado según su requisito, ejemplo 20dp * 20dp

    • Ahora, después de importar, use la imagen de dibujo importada como fuente de dibujo para su botón

    • Es más simple de esta manera ingrese la descripción de la imagen aquí

Santhosh PR
fuente
¿Cómo llegaste allí?
desarrollador de Android
Este es un complemento, creo. plugins.jetbrains.com/plugin/7658-android-drawable-importer
GeoMint
0

Es porque no lo hiciste setLevel. después de ti setLevel(1), se mostrará como quieras

Songtao Lou
fuente
0

Usando la extensión de Kotlin

val drawable = ContextCompat.getDrawable(context, R.drawable.my_icon)
// or resources.getDrawable(R.drawable.my_icon, theme)
val sizePx = 25
drawable?.setBounds(0, 0, sizePx, sizePx)
//                            (left,     top,  right, bottom)
my_button.setCompoundDrawables(drawable, null, null, null)

Sugiero crear una función de extensión en TextView ( Button la extiende ) para una fácil reutilización.

button.leftDrawable(R.drawable.my_icon, 25)

// Button extends TextView
fun TextView.leftDrawable(@DrawableRes id: Int = 0, @DimenRes sizeRes: Int) {
    val drawable = ContextCompat.getDrawable(context, id)
    val size = context.resources.getDimensionPixelSize(sizeRes)
    drawable?.setBounds(0, 0, size, size)
    this.setCompoundDrawables(drawable, null, null, null)
}
Gibolt
fuente
La pregunta era sobre Button, no sobre TextView.
Firzen
1
Deberías haber leído la respuesta. Un botón extiende TextView, por lo que puede usar esto para ambos. O cambie la extensión para extender solo un botón
Gibolt
-1

Probé las técnicas de esta publicación, pero ninguna de ellas me pareció tan atractiva. Mi solución fue usar una vista de imagen y una vista de texto y alinear la vista de imagen superior e inferior con la vista de texto. De esta manera obtuve el resultado deseado. Aquí hay un código:

<RelativeLayout
    android:id="@+id/relativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="48dp" >


    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignTop="@+id/textViewTitle"
        android:layout_alignBottom="@+id/textViewTitle"
        android:src="@drawable/ic_back" />

    <TextView
        android:id="@+id/textViewBack"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/textViewTitle"
        android:layout_alignBottom="@+id/textViewTitle"
        android:layout_toRightOf="@+id/imageView1"
        android:text="Back"
        android:textColor="@color/app_red"
        android:textSize="@dimen/title_size" />
</RelativeLayout>
Argumento ilegal
fuente
-1

Hice una clase de botones personalizados para lograr esto.

CustomButton.java

public class CustomButton extends android.support.v7.widget.AppCompatButton {

    private Drawable mDrawable;

    public CustomButton(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CustomButton,
                0, 0);

        try {
            float mWidth = a.getDimension(R.styleable.CustomButton_drawable_width, 0);
            float mHeight = a.getDimension(R.styleable.CustomButton_drawable_width, 0);

            Drawable[] drawables = this.getCompoundDrawables();
            Drawable[] resizedDrawable = new Drawable[4];

            for (int i = 0; i < drawables.length; i++) {
                if (drawables[i] != null) {
                    mDrawable = drawables[i];
                }
                resizedDrawable[i] = getResizedDrawable(drawables[i], mWidth, mHeight);
            }

            this.setCompoundDrawables(resizedDrawable[0], resizedDrawable[1], resizedDrawable[2], resizedDrawable[3]);
        } finally {
            a.recycle();
        }
    }

    public Drawable getmDrawable() {
        return mDrawable;
    }

    private Drawable getResizedDrawable(Drawable drawable, float mWidth, float mHeight) {
        if (drawable == null) {
            return null;
        }

        try {
            Bitmap bitmap;

            bitmap = Bitmap.createBitmap((int)mWidth, (int)mHeight, Bitmap.Config.ARGB_8888);

            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return drawable;
        } catch (OutOfMemoryError e) {
            // Handle the error
            return null;
        }
    }
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomButton">
        <attr name="drawable_width" format="dimension" />
        <attr name="drawable_height" format="dimension" />
    </declare-styleable>
</resources>

Uso en xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.MainActivity">

     <com.example.CustomButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableTop="@drawable/ic_hero"
            android:text="Avenger"
            custom:drawable_height="10dp"
            custom:drawable_width="10dp" />

</RelativeLayout>
Jeffy Lee
fuente
1
¿Por qué se crea una Canvasen getResizedDrawabley dibuja en ella si no se va a hacer nada con ella? Toda la función podría reducirse solo a drawable.setBounds(0, 0, mWidth, mHeight).
Antimonit