Establecer tamaño dibujable mediante programación

90

Las imágenes (íconos) tienen aproximadamente el mismo tamaño, pero necesito cambiar su tamaño para que los botones mantengan la misma altura.

¿Cómo hago esto?

Button button = new Button(this);
button.setText(apiEventObject.getTitle());
button.setOnClickListener(listener);

/*
 * set clickable id of button to actual event id
 */
int id = Integer.parseInt(apiEventObject.getId());
button.setId(id);

button.setLayoutParams(new LayoutParams(
        android.view.ViewGroup.LayoutParams.FILL_PARENT,
        android.view.ViewGroup.LayoutParams.WRAP_CONTENT));

Drawable drawable = LoadImageFromWebOperations(apiSizeObject.getSmall());
//?resize drawable here? drawable.setBounds(50, 50, 50, 50);
button.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
Weston
fuente
¿Ha encontrado la manera de cambiar el tamaño de los elementos dibujables (mapa de bits)?
Zelimir
2
Demasiado tarde, pero te preguntas por qué no llamaste setCompoundDrawables()? Intrínseco se refiere al tamaño de la imagen original en otros lugares dentro de Android, por ejemplo Drawable.getIntrinsicHeight().
William T. Mallard

Respuestas:

159

El setBounds()método no funciona para todos los tipos de contenedores (sin embargo, funcionó para algunos de mis ImageView).

Pruebe el método siguiente para escalar el propio dibujante:

// Read your drawable from somewhere
Drawable dr = getResources().getDrawable(R.drawable.somedrawable);
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
// Scale it to 50 x 50
Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, 50, 50, true));
// Set your new, scaled drawable "d"
Eric Chen
fuente
para mí, el problema aquí es que dibuja un rectángulo blanco alrededor de la imagen
dibujable
8
El constructor BitmapDrawable (Bitmap) está en desuso. Uso: Dibujable d = new BitmapDrawable (getResources (), Bitmap.createScaledBitmap (mapa de bits, 50, 50, verdadero));
Andy
1
Esto creará pixelación al escalar los elementos de diseño. Incluso si son elementos de diseño vectoriales.
Sanket Berde
probablemente quiera usarContextCompat.getDrawable(context, resourceid)
Pierre
Como nota al margen, puede crear StateListDrawableprogramáticamente y usar el addStatemétodo con ese "dibujable convertido" para que funcione para el selector's itemtamaño utilizado en setPasswordVisibilityToggleDrawable.
Fruta
31

Especifique el tamaño con setBounds(), es decir, para un uso de tamaño 50x50

drawable.setBounds(0, 0, 50, 50);

public void setBounds (int left, int top, int right, int bottom)

jkhouw1
fuente
2
Después de SetBounds, el tamaño sigue siendo el mismo. ¿Puede ser necesario invalidar?
Kostadin
6
En realidad, setBounds funciona para GradientDrawables. Simplemente no funciona para Image Drawables.
Gregm
Me funcionó cuando estaba poniendo la imagen en un botón, pero no cuando la ponía en un ImageView. El OP estaba usando un botón, pero también llamando al sabor intrínseco de la setCompoundDrawables()función.
William T. Mallard
@gregm Curiosamente, también puede establecer el tamaño de un GradientDrawable usando setSize ().
6rchid
12

Antes de aplicar .setBounds (..) intente convertir Drawable actual en ScaleDrawable

drawable = new ScaleDrawable(drawable, 0, width, height).getDrawable();

después de esto

drawable.setBounds(0, 0, width, height);

trabajará

iBog
fuente
2
¿Por qué es necesario este paso? ¿Qué envolver en una ScaleDrawablealternativa ofrece a no envolver?
azizbeko
10

No tuve tiempo de investigar por qué el método setBounds () no funciona en el mapa de bits que se puede dibujar como se esperaba, pero tengo una pequeña solución @ androbean-studio ajustada para hacer lo que setBounds debería hacer ...

/**
 * Created by ceph3us on 23.05.17.
 * file belong to pl.ceph3us.base.android.drawables
 * this class wraps drawable and forwards draw canvas
 * on it wrapped instance by using its defined bounds
 */
public class WrappedDrawable extends Drawable {

    private final Drawable _drawable;
    protected Drawable getDrawable() {
        return _drawable;
    }

    public WrappedDrawable(Drawable drawable) {
        super();
        _drawable = drawable;
    }

    @Override
    public void setBounds(int left, int top, int right, int bottom) {
        //update bounds to get correctly
        super.setBounds(left, top, right, bottom);
        Drawable drawable = getDrawable();
        if (drawable != null) {
            drawable.setBounds(left, top, right, bottom);
        }
    }

    @Override
    public void setAlpha(int alpha) {
        Drawable drawable = getDrawable();
        if (drawable != null) {
            drawable.setAlpha(alpha);
        }
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        Drawable drawable = getDrawable();
        if (drawable != null) {
            drawable.setColorFilter(colorFilter);
        }
    }

    @Override
    public int getOpacity() {
        Drawable drawable = getDrawable();
        return drawable != null
                ? drawable.getOpacity()
                : PixelFormat.UNKNOWN;
    }

    @Override
    public void draw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable != null) {
            drawable.draw(canvas);
        }
    }

    @Override
    public int getIntrinsicWidth() {
        Drawable drawable = getDrawable();
        return drawable != null
                ? drawable.getBounds().width()
                : 0;
    }

    @Override
    public int getIntrinsicHeight() {
        Drawable drawable = getDrawable();
        return drawable != null ?
                drawable.getBounds().height()
                : 0;
    }
}

uso:

// get huge drawable 
final Drawable drawable = resources.getDrawable(R.drawable.g_logo);
// create our wrapper           
WrappedDrawable wrappedDrawable = new WrappedDrawable(drawable);
// set bounds on wrapper 
wrappedDrawable.setBounds(0,0,32,32); 
// use wrapped drawable 
Button.setCompoundDrawablesWithIntrinsicBounds(wrappedDrawable ,null, null, null);

resultados

antes: ingrese la descripción de la imagen aquí después:ingrese la descripción de la imagen aquí

ceph3us
fuente
¿Cómo agregar relleno a la izquierda?
reegan29
8

Usar

textView.setCompoundDrawablesWithIntrinsicBounds()

Su minSdkVersion debe ser 17 en build.gradle

    defaultConfig {
    applicationId "com.example..."
    minSdkVersion 17
    targetSdkVersion 25
    versionCode 1
    versionName "1.0"
}

Para cambiar el tamaño dibujable:

    TextView v = (TextView)findViewById(email);
    Drawable dr = getResources().getDrawable(R.drawable.signup_mail);
    Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
    Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, 80, 80, true));

    //setCompoundDrawablesWithIntrinsicBounds (image to left, top, right, bottom)
    v.setCompoundDrawablesWithIntrinsicBounds(d,null,null,null);
Semih Fatih
fuente
3

Utilice el método de publicación para lograr el efecto deseado:

{your view}.post(new Runnable()
    {
        @Override
        public void run()
        {
            Drawable image = context.getResources().getDrawable({drawable image resource id});
            image.setBounds(0, 0, {width amount in pixels}, {height amount in pixels});
            {your view}.setCompoundDrawables(image, null, null, null);
        }
    });
OneEyeQuestion
fuente
3

Probablemente un poco tarde. Pero aquí está la solución que finalmente funcionó para mí en cada situación.

La idea es crear un dibujo personalizado con un tamaño intrínseco fijo y pasar el trabajo de dibujo al dibujo original.

Drawable icon = new ColorDrawable(){
        Drawable iconOrig = resolveInfo.loadIcon(packageManager);

        @Override
        public void setBounds(int left, int top, int right, int bottom){
            super.setBounds(left, top, right, bottom);//This is needed so that getBounds on this class would work correctly.
            iconOrig.setBounds(left, top, right, bottom);
        }

        @Override
        public void draw(Canvas canvas){
            iconOrig.draw(canvas);
        }

        @Override
        public int getIntrinsicWidth(){
            return  mPlatform.dp2px(30);
        }

        @Override
        public int getIntrinsicHeight(){
            return  mPlatform.dp2px(30);
        }
    };
Estudio Androbean
fuente
¿Qué es mPlatform?
Batsheva
@batsheva Es solo algo que usa para la conversión de dp a px ...
desarrollador de Android
2

jkhouw1 respuesta es correcta, pero carece de algunos detalles, ver a continuación:

Es mucho más fácil para al menos API> 21. Supongamos que tenemos VectorDrawable de recursos (código de ejemplo para recuperarlo):

val iconResource = context.resources.getIdentifier(name, "drawable", context.packageName)
val drawable = context.resources.getDrawable(iconResource, null)

Para ese VectorDrawable, simplemente configure el tamaño deseado:

drawable.setBounds(0, 0, size, size)

Y mostrar dibujable en el botón:

button.setCompoundDrawables(null, drawable, null, null)

Eso es. ¡Pero tenga en cuenta que debe usar setCompoundDrawables (no la versión intrínseca)!

Ilia Petukhov
fuente
0

Puede crear una subclase del tipo de vista y anular el método onSizeChanged.

Quería tener elementos de diseño compuestos de escala en mis vistas de texto que no me obligaran a perder el tiempo definiendo elementos de diseño de mapa de bits en xml, etc. y lo hice de esta manera:

public class StatIcon extends TextView {

    private Bitmap mIcon;

    public void setIcon(int drawableId) {
    mIcon = BitmapFactory.decodeResource(RIApplication.appResources,
            drawableId);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if ((w > 0) && (mIcon != null))
            this.setCompoundDrawablesWithIntrinsicBounds(
                null,
                new BitmapDrawable(Bitmap.createScaledBitmap(mIcon, w, w,
                        true)), null, null);

        super.onSizeChanged(w, h, oldw, oldh);
    }

}

(Tenga en cuenta que usé w dos veces, no h, ya que en este caso estaba colocando el ícono sobre el texto y, por lo tanto, el ícono no debería tener la misma altura que la vista de texto)

Esto se puede aplicar a elementos de diseño de fondo, o cualquier otra cosa que desee cambiar de tamaño en relación con el tamaño de su vista. onSizeChanged () se llama la primera vez que se crea la Vista, por lo que no necesita ningún caso especial para inicializar el tamaño.

Zulaxia
fuente
0

Puedes intentarlo button.requestLayout(). Cuando se cambia el tamaño del fondo, es necesario volver a medir y diseñar, pero no lo hará

Xiaomei
fuente
0

Conseguí esto funcionando usando LayerDrawable:

fun getResizedDrawable(drawable: Drawable, scale: Float) =
    LayerDrawable(arrayOf(drawable)).also { it.setLayerSize(0, (drawable.intrinsicWidth * scale).toInt(), (drawable.intrinsicHeight * scale).toInt()) }

fun getResizedDrawable(drawable: Drawable, scalex: Float, scaleY: Float) =
    LayerDrawable(arrayOf(drawable)).also { it.setLayerSize(0, (drawable.intrinsicWidth * scalex).toInt(), (drawable.intrinsicHeight * scaleY).toInt()) }

fun getResizedDrawableUsingSpecificSize(drawable: Drawable, newWidth: Int, newHeight: Int) =
    LayerDrawable(arrayOf(drawable)).also { it.setLayerSize(0, newWidth, newHeight) }

Ejemplo:

val drawable = AppCompatResources.getDrawable(this, android.R.drawable.sym_def_app_icon)!!
val resizedDrawable = getResizedDrawable(drawable, 3f)
textView.setCompoundDrawablesWithIntrinsicBounds(resizedDrawable, null, null, null)
imageView.setImageDrawable(resizedDrawable)
desarrollador de Android
fuente
-1

Puede usar LayerDrawable desde una sola capa y el método setLayerInset:

Drawable[] layers = new Drawable[1];
layers[0] = application.getResources().getDrawable(R.drawable.you_drawable);

LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.setLayerInset(0, 10, 10, 10, 10);
Valery Miller
fuente
-1

Ha pasado un tiempo desde que se hizo la pregunta,
pero todavía no está claro para muchos cómo hacer esto.

Es bastante simple en ese caso cuando usa un Drawable como un dibujable compuesto en un TextView (Botón).

Entonces 2 cosas que tienes que hacer:

1.Establecer límites:

drawable.setBounds(left, top, right, bottom)

2.Configure el dibujable apropiadamente (sin usar límites intrínsecos):

button.setCompoundDrawablesRelative(drawable, null, null, null)
  • No es necesario utilizar mapas de bits
  • No hay soluciones alternativas como ScaleDrawable ColorDrawableoLayerDrawable (lo que definitivamente se crea para otros fines)
  • ¡Sin necesidad de diseños personalizados!
  • No hay soluciones con el post
  • Es una solución nativa y simple, tal como Android espera que lo haga.
Leo Droidcoder
fuente
-42
Button button = new Button(this);
Button = (Button) findViewById(R.id.button01);

Utilice Button.setHeight()o Button.setWeight()y establezca un valor.

usuario564612
fuente
9
eso solo establece la altura del botón, no la altura del elemento de diseño. Quiero establecer el ancho / alto del dibujable (especialmente si es más grande que la altura del botón de configuración).
21
Sabes que puedes borrar la respuesta, ¿no?
Iharob Al Asimi