491

I'm dynamically creating buttons. I styled them using XML first, and I'm trying to take the XML below and make it programattic.

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

This is what I have so far. I can do everything but the 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
  • 38,263
  • 17
  • 115
  • 131

14 Answers14

1145

You can use the setCompoundDrawables method to do this. See the example here. I used this without using the setBounds and it worked. You can try either way.

UPDATE: Copying the code here incase the link goes down

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

or

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

or

txtVw.setCompoundDrawablesWithIntrinsicBounds(R.drawable.smiley, 0, 0, 0);
Manaus
  • 387
  • 4
  • 9
Varun
  • 32,359
  • 4
  • 46
  • 42
  • @Varun, @Tigger: I have a problem with this: My filemanager shows folders in a listview with textviews and a folder icon as a `drawableLeft`. I tried your suggestions here to set a "forbidden icon" when you click in a folder without read permissions, and it works. However, when you change folders and the adapter is reloaded, the forbidden icon persists (that is, `drawableLeft` are not redrawn). Do you know how to apply `notifyDataSetChanged` also for the `drawableLeft`, without doing a loop? Thanks! – Luis A. Florit Sep 19 '13 at 02:50
  • @LuisA.Florit It sounds like you have a question related to the redrawing of a `Listview` item when the data changes - which does not really relate to this question or answer. I suggest you post a question instead of a comment. – Tigger Sep 19 '13 at 03:42
  • @Tigger: Well, I reverted back the icon using your trick also, and a loop over the forbidden dirs. Maybe this is better than redrawing all the ListView items... Thanks anyway! – Luis A. Florit Sep 19 '13 at 03:47
  • 4
    I'm seeing something strange in my app. The `setCompoundDrawablesWithIntrinsicBounds( 0, 0, R.drawable.money, 0 )` doesn't work, if I define the drawableRight in the layout.xml. If I set the original icon inside `onCreate()`, then the change works. Could it be related to API 19? – injecteer Jan 20 '14 at 22:29
  • Example link is not opening. Is there any alternative link? – Yogesh Umesh Vaity Jul 15 '16 at 09:53
  • As described in this [answer](http://stackoverflow.com/a/18279169/43051), using this code is safer to avoid removing existing drawables: `Drawable[] drawables = textViewExample.getCompoundDrawables(); textViewExample.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, drawables[1], drawables[2], drawables[3]);` – Jérémy Reynaud Aug 17 '16 at 13:48
  • @Varun Hi sir,How to remove that add image in edittext. – Gowthaman M Jul 24 '17 at 07:17
  • what about `drawableStart` and `drawableEnd` ? – MHSFisher Dec 31 '18 at 07:35
  • Actually must use -> ContextCompat.getDrawable(context, R.drawable.your_drawable) – Ruben Caster Nov 25 '20 at 09:04
112

Simply you can try this also

txtVw.setCompoundDrawablesWithIntrinsicBounds(R.drawable.smiley, 0, 0, 0);
Community
  • 1
  • 1
Jignesh Ansodariya
  • 11,683
  • 21
  • 74
  • 107
  • 4
    R.drawable.smiley should be in the place of the first 0 (the first parameter) not the last because the definition of this method is: {public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom)} – arniotaki Nov 14 '14 at 08:40
  • How can I add padding around this, too? There's not much padding between the drawable and the text this way. – AdamMc331 Feb 06 '17 at 17:08
25

Kotlin Version

Use below snippet to add a drawable left to the button:

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

.

Important Point in Using Android Vector Drawable

When you are using an android vector drawable and want to have backward compatibility for API below 21, add the following codes to:

In app level build.gradle:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

In Application class:

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
    }

}
aminography
  • 18,195
  • 11
  • 51
  • 57
22
myEdtiText.setCompoundDrawablesWithIntrinsicBounds(R.drawable.smiley, 0, 0, 0);
aminography
  • 18,195
  • 11
  • 51
  • 57
gnganapath
  • 827
  • 10
  • 15
21

For me, it worked:

button.setCompoundDrawablesWithIntrinsicBounds(com.example.project1.R.drawable.ic_launcher, 0, 0, 0);
SMR
  • 6,320
  • 2
  • 32
  • 55
swapnil saha
  • 1,220
  • 10
  • 10
8

If you are using drawableStart, drawableEnd, drawableTop or drawableBottom; you must use "setCompoundDrawablesRelativeWithIntrinsicBounds"

edittext.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.anim_search_to_close, 0)
Mete
  • 2,627
  • 1
  • 22
  • 35
7

Worked for me. To set drawable at the right

tvBioLive.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_close_red_400_24dp, 0)
Shaon
  • 1,404
  • 14
  • 17
6

I did this:

 // 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
  • 525
  • 1
  • 9
  • 15
4

as @Jérémy Reynaud pointing out, as described in this answer, the safest way to set the left drawable without changing the values of the other drawables (top, right, and bottom) is by using the previous values from the button with 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]);

So all your previous drawable will be preserved.

ישו אוהב אותך
  • 22,515
  • 9
  • 59
  • 80
3

Following is the way to change the color of the left icon in edit text and set it in left side.

 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
  • 554
  • 6
  • 14
3

Add a Kotlin Extension

If you are going to be doing this frequently, adding an extension makes your code more readable. Button extends TextView; use Button if you want to be more narrow.

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

To use the extension, simply call

view.leftDrawable(R.drawable.my_drawable)

Anytime you need to clear, don't pass a param or make another extension called removeDrawables

Gibolt
  • 24,018
  • 9
  • 129
  • 89
2

Might be helpful:

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);
Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57
Muhaiminur Rahman
  • 2,459
  • 17
  • 22
0

Try this:

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));
}
Manaus
  • 387
  • 4
  • 9
Maifee Ul Asad
  • 1,912
  • 2
  • 14
  • 40
-8

Try this:

((Button)btn).getCompoundDrawables()[0].setAlpha(btn.isEnabled() ? 255 : 100);
Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57