Como definir programaticamente drawableLeft no botão Android?

442

Estou criando botões dinamicamente. Eu os estilizei usando XML primeiro, e estou tentando pegar o XML abaixo e torná-lo programático.

<Button
    android:id="@+id/buttonIdDoesntMatter"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:text="buttonName"
    android:drawableLeft="@drawable/imageWillChange"
    android:onClick="listener"
    android:layout_width="fill_parent">
</Button>

É isso que eu tenho até agora. Eu posso fazer tudo, menos o drawable.

linear = (LinearLayout) findViewById(R.id.LinearView);
Button button = new Button(this);
button.setText("Button");
button.setOnClickListener(listener);
button.setLayoutParams(
    new LayoutParams(
        android.view.ViewGroup.LayoutParams.FILL_PARENT,         
        android.view.ViewGroup.LayoutParams.WRAP_CONTENT
    )
);      

linear.addView(button);
Tim
fonte

Respostas:

1054

Você pode usar o setCompoundDrawablesmétodo para fazer isso. Veja o exemplo aqui . Eu usei isso sem usar setBoundsoe funcionou. Você pode tentar de qualquer maneira.

UPDATE : Copiando o código aqui, caso o link seja desativado

Drawable img = getContext().getResources().getDrawable(R.drawable.smiley);
img.setBounds(0, 0, 60, 60);
txtVw.setCompoundDrawables(img, null, null, null);

ou

Drawable img = getContext().getResources().getDrawable(R.drawable.smiley);
txtVw.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null);

ou

txtVw.setCompoundDrawablesWithIntrinsicBounds(R.drawable.smiley, 0, 0, 0);
Varun
fonte
@Varun, @Tigger: Eu tenho um problema com isso: Meu gerenciador de arquivos mostra pastas em uma lista com vistas de texto e um ícone de pasta como a drawableLeft. Tentei suas sugestões aqui para definir um "ícone proibido" quando você clica em uma pasta sem permissões de leitura e funciona. No entanto, quando você altera as pastas e o adaptador é recarregado, o ícone proibido persiste (ou seja, drawableLeftnão é redesenhado). Você sabe como se inscrever notifyDataSetChangedtambém para o drawableLeft, sem fazer um loop? Obrigado!
Luis A. Florit 19/09/2013
@ LuisA.Florit Parece que você tem uma pergunta relacionada ao redesenho de um Listviewitem quando os dados são alterados - o que realmente não está relacionado a essa pergunta ou resposta. Sugiro que você publique uma pergunta em vez de um comentário.
quer
@ Tigger: Bem, eu revertei o ícone usando seu truque também, e um loop sobre os diretórios proibidos. Talvez seja melhor do que redesenhar todos os itens do ListView ... De qualquer forma, obrigado!
Luis A. Florit
3
Estou vendo algo estranho no meu aplicativo. A setCompoundDrawablesWithIntrinsicBounds( 0, 0, R.drawable.money, 0 )não funcionar, se eu definir o drawableRight na layout.xml. Se eu definir o ícone original onCreate(), a alteração funcionará. Poderia estar relacionado à API 19?
usar o seguinte comando
O link de exemplo não está sendo aberto. Existe algum link alternativo?
Yogesh Umesh Vaity
100

Simplesmente você pode tentar isso também

txtVw.setCompoundDrawablesWithIntrinsicBounds(R.drawable.smiley, 0, 0, 0);
Jignesh Ansodariya
fonte
4
R.drawable.smiley deve estar no lugar do primeiro 0 (o primeiro parâmetro) e não o último, porque a definição desse método é: {public void setCompoundDrawablesWithIntrinsicBounds (int left, int top, int right, int bottom)}
arniotaki
Como posso adicionar preenchimento também? Não há muito preenchimento entre o drawable e o texto dessa maneira.
31417 AdamMc331
16

Kotlin Version

Use o snippet abaixo para adicionar um desenho à esquerda do botão:

val drawable = ContextCompat.getDrawable(context, R.drawable.ic_favorite_white_16dp)
button.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)

.

Important Point in Using Android Vector Drawable

Quando você estiver usando um drawable de vetor android e quiser ter compatibilidade com versões anteriores da API abaixo de 21 , adicione os seguintes códigos a:

No nível do aplicativo build.gradle:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

Na classe Application:

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
    }

}
aminografia
fonte
Uma maneira mais simples que também funciona para mim: button.setCompoundDrawablesWithIntrinsicBounds (getDrawable (R.drawable.ic_favorite_white_16dp), null, null, null)
juangalf
2
Você está certo, mas Context#.getDrawable(resId)está obsoleto, portanto, usá-lo pode causar alguns problemas.
Aminografia 13/08/19
Funciona sem adicionar na classe Application, pois não tenho uma.
Mark Delphi
15

Para mim, funcionou:

button.setCompoundDrawablesWithIntrinsicBounds(com.example.project1.R.drawable.ic_launcher, 0, 0, 0);
swapnil saha
fonte
13
myEdtiText.setCompoundDrawablesWithIntrinsicBounds(R.drawable.smiley, 0, 0, 0);
gnganpath
fonte
4

Eu fiz isso:

 // Left, top, right, bottom drawables.
            Drawable[] drawables = button.getCompoundDrawables();
            // get left drawable.
            Drawable leftCompoundDrawable = drawables[0];
            // get new drawable.
            Drawable img = getContext().getResources().getDrawable(R.drawable.ic_launcher);
            // set image size (don't change the size values)
            img.setBounds(leftCompoundDrawable.getBounds());
            // set new drawable
            button.setCompoundDrawables(img, null, null, null);
user1564762
fonte
4

Se você estiver usando drawableStart , drawableEnd , drawableTop ou drawableBottom ; você deve usar " setCompoundDrawablesRelativeWithIntrinsicBounds "

edittext.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.anim_search_to_close, 0)
Mete
fonte
3

Trabalhou para mim. Para definir o drawable à direita

tvBioLive.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_close_red_400_24dp, 0)
Shaon
fonte
2

como @ Jérémy Reynaud apontando, conforme descrito nesta resposta , a maneira mais segura de definir o drawable esquerdo sem alterar os valores dos outros drawables (superior, direito e inferior) é usando os valores anteriores do botão com setCompoundDrawablesWithIntrinsicBounds :

Drawable leftDrawable = getContext().getResources()
                          .getDrawable(R.drawable.yourdrawable);

// Or use ContextCompat
// Drawable leftDrawable = ContextCompat.getDrawable(getContext(),
//                                        R.drawable.yourdrawable);

Drawable[] drawables = button.getCompoundDrawables();
button.setCompoundDrawablesWithIntrinsicBounds(leftDrawable,drawables[1],
                                               drawables[2], drawables[3]);

Portanto, todo o seu drawable anterior será preservado.

ישו אוהב אותך
fonte
2

A seguir, é possível alterar a cor do ícone esquerdo no texto de edição e configurá-lo no lado esquerdo.

 Drawable img = getResources().getDrawable( R.drawable.user );
img.setBounds( 0, 0, 60, 60 );
mNameEditText.setCompoundDrawables(img,null, null, null);

int color = ContextCompat.getColor(this, R.color.blackColor);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    DrawableCompat.setTint(img, color);

} else {
    img.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
Rajneesh Shukla
fonte
1

Pode ser útil:

TextView location;
location=(TextView)view.findViewById(R.id.complain_location);
//in parameter (left,top,right,bottom) any where you wnat to put
location.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.arrow,0);
Muhaiminur Rahman
fonte
1

Adicionar uma extensão Kotlin

Se você fizer isso com frequência, adicionar uma extensão torna seu código mais legível. O botão estende o TextView; use o botão se você quiser ser mais estreito.

fun TextView.leftDrawable(@DrawableRes id: Int = 0) {
    this.setCompoundDrawablesWithIntrinsicBounds(id, 0, 0, 0)
}

Para usar o ramal, basta ligar para

view.leftDrawable(R.drawable.my_drawable)

Sempre que precisar limpar, não passe um parâmetro ou faça outra extensão chamada removeDrawables

Gibolt
fonte
0

Tente o seguinte:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
     fillButton[i].setBackground(getBaseContext().getResources().getDrawable(R.drawable.drawable_name));
}
else {
    fillButton[i].setBackgroundColor(Color.argb(255,193,234,203));
}
Maifee Ul Asad
fonte
-8

Tente o seguinte:

((Button)btn).getCompoundDrawables()[0].setAlpha(btn.isEnabled() ? 255 : 100);
user2969017
fonte
myEdtiText.setCompoundDrawablesWithIntrinsicBounds (R.drawable.smiley, 0, 0, 0); funciona
Debasish Ghosh