Como posso reduzir o drawable em um botão?

87

como posso tornar o drawable em um botão menor? O ícone é muito grande, na verdade mais alto que o botão. Este é o código que estou 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>

A parte superior é como deve ser, e a parte inferior como deve ser agora.

A parte superior é como deve ser, e a parte inferior como deve ser agora.

Tentei fazer isso, mas não há imagem exibida. :-(

    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
fonte
Seria melhor se você carregasse uma imagem do que está obtendo e do que está tentando fazer. Obrigado.
Lalit Poptani
Você pode definir seu botão personalizado para definir o tamanho dos drawables. Veja minha resposta aqui stackoverflow.com/a/31916731/2308720
Oleksandr
Eu sei que isso é de 2011 ... mas na verdade eu prefiro a aparência do botão com a câmera saindo dos limites do botão - eu teria deixado do jeito que estava ... apenas dizendo :)
killercowuk

Respostas:

70

Você deve usar um ImageButton e especificar a imagem em android:src, e definir android:scaletypecomofitXY


Configurando drawable dimensionado no 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
fonte
Se você definir o drawable no código, poderá redimensioná-lo com base na altura do botão e, em seguida, defini-lo.
Ronnie
Agora a imagem é exibida, mas não é redimensionada! Tentei valores entre 0.1f e 10f. Qualquer ideia? Obrigado pela ajuda ...
Reto
Experimente istodrawable.setBounds(0, 0, drawable.getIntrinsicWidth()*0.5, drawable.getIntrinsicHeight()*0.5);
Ronnie
Se isso redimensionar o drawable, você pode remover a parte escalonável e usar o drawable diretamente.
Ronnie
2
Devemos definir nossos próprios valores para scaleWidth e scaleHeight? Eles são apenas descritivos?
SametSahin
89

Eu encontrei uma solução XML muito simples e eficaz que não requer ImageButton

Faça um arquivo drawable para sua imagem como abaixo e use-o 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>

Você pode definir o tamanho da imagem com android:widthe android:heightpropriedades.

Dessa forma, você pode obter pelo menos o mesmo tamanho para telas diferentes.

A desvantagem é que não é exatamente como fitXY, que dimensionaria a largura da imagem para caber em X e dimensionaria a altura da imagem de acordo.

companheiro
fonte
9
Esta deve ser a resposta aceita. Se alguém não quiser um ImageButton (por exemplo, porque deseja texto, etc.), essa resposta permite imagens em tamanho dentro de um Botão com Texto mais código zero.
Aço Reciclado de
3
Fiz um novo drawable como este e, em seguida, android:drawableTopadicionei o novo drawable. Não importa quais valores de largura / altura eu defina, ele me mostra o padrão.
driftking9987
9
Não parece funcionar para versões do Android abaixo do Lollipop.
Jyotman Singh
32
altura, largura funcionam apenas no nível de API 23 e superior. Não compatível com versões anteriores.
Palak Darji de
Eu concordo, esta é de longe a melhor solução
Senzo Malinga
10

Os botões não redimensionam suas imagens internas.

Minha solução não requer manipulação de código.

Ele usa um layout com TextView e ImageView.

O plano de fundo do layout deve ter o drawable 3d vermelho.

Pode ser necessário definir o atributo xml android: scaleType .

Exemplo:

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

BTW:

  1. Contar com ícones de resolução diferente pode resultar em uma IU imprevisível (ícone muito grande ou muito pequeno)
  2. O texto na visualização de texto (incluindo nos botões) não preenche o componente. Este é um problema do Android e não sei como resolvê-lo.
  3. Você pode usá-lo como um include.

Boa sorte

AlikElzin-kilaka
fonte
RE: TextViews, se eu quiser que a visualização seja o menor possível, defino o preenchimento para zero. Caso contrário, parece ter um preenchimento padrão.
William T. Mallard
6

Use um ScaleDrawable como Abhinav sugeriu.

O problema é que o drawable não aparece então - é algum tipo de bug no ScaleDrawables. você precisará alterar o "nível" programaticamente. Isso deve funcionar para todos os botões:

// 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
fonte
Agradável. Acho que posso usar isso em um futuro próximo!
Abhinav
@zeh, agora descobri que funciona se você executar o código acima antes de setContentView, caso contrário, não funciona. Poderia ser melhor se você adicionar isso à sua postagem.
Buddy
Por algum motivo, minha solução acima não funciona em todas as versões do Android.
Buddy
6

Meu DiplayScaleHelper, que funciona perfeitamente:

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());
                }
            }
        }
    }
}
Владимир Фишер
fonte
4

Você pode chamar setBoundsos drawables "compostos" para modificar o tamanho da imagem.

Experimente este código para dimensionar automaticamente o drawable de seu botão:

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

definido por esta função:

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

Esteja ciente de que isso pode não ser acionado em onCreate()uma atividade, porque a altura e a largura do botão (ainda) não estão disponíveis lá. Chame isso onWindowFocusChanged()ou use esta solução para chamar a função.

Editado:

A primeira encarnação desta função não funcionou corretamente. Ele usou o código userSeven7s para dimensionar a imagem, mas o retorno ScaleDrawable.getDrawable() não parece funcionar (nem retornar ScaleDrawable) para mim.

O código modificado usa setBoundspara fornecer os limites para a imagem. O Android se encaixa a imagem nesses limites.

yonojoy
fonte
Obrigado por ter dito para não ligar onCreate().
Binarian
1

Estou fazendo como abaixo. Isso cria uma imagem de tamanho 100x100 no botão independente da imagem de entrada.

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

Não usando ScaleDrawablenenhum. Não usar button.setCompoundDrawablesRelativeWithIntrinsicBounds()resolveu meu problema, já que parece usar limites intrínsecos (tamanho da imagem de origem) em vez dos limites que você acabou de definir.

LP
fonte
0

Você pode usar drawables de tamanhos diferentes que são usados ​​com densidades / tamanhos de tela diferentes, etc. para que sua imagem fique correta em todos os dispositivos.

Veja aqui: http://developer.android.com/guide/practices/screens_support.html#support

HXCaine
fonte
Eu uso a mesma imagem em lugares diferentes. É por isso que não consigo redimensioná-lo, ele deve ser exibido no tamanho que desejo.
Reto
0

Você tentou envolver sua imagem em um ScaleDrawable e usá-lo em seu botão?

Abhinav
fonte
2
Apenas tentei isso, no entanto, meu ScaleDrawable não é exibido. :-( Mesmo não em um ImageView. Peguei o código de amostra e apenas substituí o drawable. Alguma ideia de por que isso não funciona?
Reto
Eu tive o mesmo problema. ScaleDrawableseria perfeito, mas simplesmente não funciona. Parece ter algo a ver com "níveis". Mais informações aqui (e algumas soluções alternativas que não são perfeitas): stackoverflow.com/questions/5507539/…
zeh
(editar) consertou com algum código genérico! Solução aqui que ainda permite que você use ScaleDrawables: stackoverflow.com/a/13706836/439026
zeh
0

Aqui está a função que criei para dimensionar drawables vetoriais. Usei-o para definir o drawable composto TextView.

/**
 * 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
fonte
0
  • Usando o recurso "BATCH DRAWABLE IMPORT", você pode importar um tamanho personalizado dependendo do seu exemplo de requisito 20dp * 20dp

    • Agora, após a importação, use drawable_image importado como drawable_source para seu botão

    • É mais simples assim insira a descrição da imagem aqui

Santhosh PR
fonte
Como você chegou lá?
desenvolvedor Android
0

É porque você não fez setLevel. depois de você setLevel(1), será exibido como você quiser

Songtao Lou
fonte
0

Usando a extensão 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)

Eu sugiro criar uma função de extensão no TextView ( Button extends it ) para fácil reutilização.

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
fonte
A pergunta era sobre Button, não TextView.
Firzen
1
Você deveria ter lido a resposta. Um Button estende TextView, então você pode usar isso para ambos. Ou altere a extensão para estender apenas um botão
Gibolt
-1

Experimentei as técnicas deste post, mas não achei nenhuma delas tão atraente. Minha solução foi usar uma visualização de imagem e uma visualização de texto e alinhar a parte superior e inferior da visualização de imagem com a visualização de texto. Assim obtive o resultado desejado. Aqui estão alguns códigos:

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

Eu fiz uma classe de botão personalizado para conseguir isso.

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 em 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
fonte
1
Por que você criar um Canvasem getResizedDrawablee desenhar nele, se você não vai fazer nada com ele? Toda a função pode ser reduzida apenas a drawable.setBounds(0, 0, mWidth, mHeight).
Antimonit