Definir o tamanho do drawable programaticamente

92

As imagens (ícones) têm aproximadamente o mesmo tamanho, mas preciso redimensioná-las para que os botões permaneçam com a mesma altura.

Como eu faço isso?

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
fonte
Você descobriu como redimensionar drawable (Bitmap)?
Zelimir
2
Muito tarde, mas está se perguntando por que você não ligou setCompoundDrawables()? Intrínseca refere-se ao tamanho da imagem original em outros lugares dentro Android, por exemplo Drawable.getIntrinsicHeight().
William T. Mallard

Respostas:

160

O setBounds()método não funciona para todos os tipos de contêiner (no entanto, funcionou para alguns dos meus ImageView).

Experimente o método abaixo para dimensionar o próprio drawable:

// 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
fonte
para mim, o problema aqui é que ele desenha um retângulo branco ao redor da imagem drawable
noloman
8
O construtor BitmapDrawable (Bitmap) está obsoleto. Use: Drawable d = new BitmapDrawable (getResources (), Bitmap.createScaledBitmap (bitmap, 50, 50, true));
Andy
1
Isso criará pixelização ao aumentar drawables. Mesmo que sejam drawables vetoriais.
Sanket Berde,
provavelmente deseja usarContextCompat.getDrawable(context, resourceid)
Pierre
Como uma observação lateral, você pode criar StateListDrawableprogramaticamente e usar o addStatemétodo com esse "drawable convertido" para fazê-lo funcionar para o selector's itemtamanho usado em setPasswordVisibilityToggleDrawable.
Fruta de
31

Especifique o tamanho com setBounds(), ou seja, para um tamanho 50x50, use

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

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

jkhouw1
fonte
2
Depois de SetBounds, o tamanho permanece o mesmo. Pode ser necessário algum invalidate?
Kostadin de
6
Na verdade, setBounds funciona para GradientDrawables. Simplesmente não funciona para Drawables de imagens.
gregm
Funcionou para mim quando coloquei a imagem em um botão, mas não quando a coloquei em um ImageView. O OP estava usando um botão, mas também chamando o sabor intrínseco da setCompoundDrawables()função.
William T. Mallard
@gregm Curiosamente, você também pode definir o tamanho de um GradientDrawable usando setSize ().
6rchid
12

Antes de aplicar .setBounds (..) tente converter Drawable atual em ScaleDrawable

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

depois disso

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

vai funcionar

iBog
fonte
2
Por que essa etapa é necessária? Qual embalagem em um ScaleDrawableoferece alternativa ao não embalagem?
azizbekian
10

Eu não tive tempo para descobrir por que o método setBounds () não está funcionando no drawable de bitmap como esperado, mas eu fiz alguns ajustes na solução @ androbean-studio para fazer o que setBounds deve fazer ...

/**
 * 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: insira a descrição da imagem aqui depois:insira a descrição da imagem aqui

Ceph3us
fonte
como adicionar preenchimento à esquerda?
reegan29
8

Usar

textView.setCompoundDrawablesWithIntrinsicBounds()

Sua minSdkVersion deve ser 17 em build.gradle

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

Para alterar o tamanho do drawable:

    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
fonte
3

Use o método de postagem para obter o efeito desejado:

{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
fonte
3

Provavelmente um pouco tarde. Mas aqui está a solução que finalmente funcionou para mim em todas as situações.

A ideia é criar um drawable personalizado com tamanho intrínico fixo e passar o trabalho de desenho para o drawable 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);
        }
    };
Androbean Studio
fonte
o que é mPlatform?
batsheva
@batsheva É apenas algo que ele usa para conversão de dp para px ...
desenvolvedor Android
2

A resposta jkhouw1 está correta, mas faltam alguns detalhes, veja abaixo:

É muito mais fácil para pelo menos API> 21. Suponha que temos VectorDrawable de recursos (código de exemplo para recuperá-lo):

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

Para esse VectorDrawable, basta definir o tamanho desejado:

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

E mostrar drawable no botão:

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

É isso aí. Mas observe para usar setCompoundDrawables (não a versão intrínseca)!

Ilia Petukhov
fonte
1

Isso está 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) }

Exemplo:

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)
desenvolvedor android
fonte
0

Você pode criar uma subclasse do tipo de visualização e substituir o método onSizeChanged.

Eu queria ter drawables compostos de dimensionamento em minhas visualizações de texto que não exigissem que eu mexesse com a definição de drawables de bitmap em xml etc. e fiz desta forma:

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);
    }

}

(Observe que usei w duas vezes, não h, pois neste caso eu estava colocando o ícone acima do texto e, portanto, o ícone não deve ter a mesma altura que a visualização do texto)

Isso pode ser aplicado a drawables de fundo ou qualquer outra coisa que você queira redimensionar em relação ao tamanho da sua visualização. onSizeChanged () é chamado na primeira vez que a visualização é feita, então você não precisa de nenhum caso especial para inicializar o tamanho.

Zulaxia
fonte
0

Você pode tentar button.requestLayout(). Quando o tamanho do fundo é alterado, ele precisa medir e fazer o layout novamente, mas não vai resolver

Xiaomei
fonte
-1

Você pode usar LayerDrawable de apenas uma camada e o 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
fonte
-1

Já faz um tempo desde que a pergunta foi feita,
mas ainda não está claro para muitos como fazer essa coisa simples.

É muito simples nesse caso, quando você usa um Drawable como um drawable composto em um TextView (Button).

Portanto, 2 coisas que você deve fazer:

1. Definir limites:

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

2. Defina o drawable de forma adequada (sem usar limites intrínsecos):

button.setCompoundDrawablesRelative(drawable, null, null, null)
  • Não há necessidade de usar bitmaps
  • Sem soluções alternativas como ScaleDrawable ColorDrawableou LayerDrawable(o que é definitivamente criado para outros fins)
  • Não há necessidade de drawables personalizados!
  • Sem soluções alternativas com o post
  • É uma solução nativa e simples, exatamente como o Android espera que você faça.
Leo Droidcoder
fonte
-43
Button button = new Button(this);
Button = (Button) findViewById(R.id.button01);

Use Button.setHeight()ou Button.setWeight()e defina um valor.

user564612
fonte
9
isso apenas define a altura do botão, não a altura do drawable. quero definir a largura / altura do drawable (especialmente se for maior do que a altura do botão definido).
23
Você sabe que pode deletar a resposta, não é?
Iharob Al Asimi de