127

I have some buttons like this in my app:

    <Button
        android:id="@+id/bSearch"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:text="Search"
        android:textSize="24sp" />

I'm trying to create a same button with text and a icon. android:drawableLeft doesn't work for me (Maybe it would, but i don't know how to set a max height to the icon).

So i created a LinearLayout with a ImageView and a TextView and made it act like a button:

    <LinearLayout
        android:id="@+id/bSearch2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:drawable/btn_default"
        android:clickable="true"
        android:padding="16dp"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="5dp"
            android:adjustViewBounds="true"
            android:maxHeight="30dp"
            android:maxWidth="30dp"
            android:scaleType="fitCenter"
            android:src="@drawable/search_icon" />

        <TextView
            android:id="@+id/tvSearchCaption"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="24sp"
            android:paddingRight="30dp"
            android:gravity="center"
            android:text="Search" />
    </LinearLayout>

My new button is exactly what i want (font size, icon and text placement). But it doesn't look like my default buttons:

enter image description here

So i tried, to change the background and the text color of my new Button:

Button Search = (Button) findViewById(R.id.bSearch);
LinearLayout bSearch2 = (LinearLayout) findViewById(R.id.bSearch2);
bSearch2.setBackground(bSearch.getBackground());
TextView tvSearchCaption = (TextView)findViewById(R.id.tvSearchCaption);
tvSearchCaption.setTextColor(bSearch.getTextColors().getDefaultColor());

This gives a strange result, my old button, gets messed up:

enter image description here

When i change the order of these two buttons in the XML, so the "new button" goes first, it makes another strange result:

enter image description here

Now i noticed, that when i try to press the old button, the new one gets pressed.

Any ideas?

Dusan
  • 3,284
  • 6
  • 25
  • 46

11 Answers11

357

Try this one.

<Button
    android:id="@+id/bSearch"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:text="Search"
    android:drawableLeft="@android:drawable/ic_menu_search"
    android:textSize="24sp"/>
Liem Vo
  • 5,149
  • 2
  • 18
  • 16
  • 3
    That looks exactly how i want it, but i want to use my own icons, not the default android ones. My icons are bigger size. Does that mean, i need to create smaller bitmaps for every resolution? Is there some parameter which lets me control the icon size? – Dusan Apr 09 '14 at 14:57
  • That is correct. You need create different image size for each resolution – Liem Vo Apr 09 '14 at 15:07
  • Ok, thanks for your help, but now i have another question... My icons are light, because the text is white on a dark button, like you can see in the images in my question. The app is set, to use a theme which is availible in the android version. My examples are from android 4.3. When the app runs on android 2.3.3, the default buttons are light with dark text. Kinda something like the button on my first image. Is there a way to provide an alternative bitmap for the icon running on older devices. I hope you understand my question :) – Dusan Apr 09 '14 at 15:20
  • That is a good question. You can define different style for your icon, text cooler in style for each API level (it mean android OS version). You can see the values-v11, values-v14 folders. – Liem Vo Apr 09 '14 at 15:24
  • I'll give it a try. My theme is also set via the styles.xml in those folders. – Dusan Apr 09 '14 at 15:27
  • No it is default from Android. You can edit your theme in those folders :) – Liem Vo Apr 09 '14 at 15:31
  • Can you use also resources in the mipmap folder? – Antonio Sesto Mar 23 '15 at 21:28
  • How can I resize the images? – Isuru Aug 11 '15 at 10:36
  • @AntonioSesto: Yes you can @Isuru; Image will be put in different resolution folder. Is it correct your question? – Liem Vo Apr 26 '16 at 03:37
  • The important note - it doesn't work for API=18 and below. You will get a runtime crash with "android:drawableLeft". – Maxim Firsoff Sep 19 '17 at 07:17
  • @MaximFirsoff Can you share the crash log? – Liem Vo Sep 19 '17 at 07:19
  • FATAL EXCEPTION: main android.view.InflateException: Binary XML file line #63: Error inflating class Button.... The full log as a screenshot is here: http://my.jetscreenshot.com/3084/20170919-dlry-91kb – Maxim Firsoff Sep 19 '17 at 07:22
  • @MaximFirsoff I build with: `minSdkVersion 14 targetSdkVersion 18` I don't get the crash like you. – Liem Vo Sep 19 '17 at 07:40
  • @MaximFirsoff without crash after building and running – Liem Vo Sep 19 '17 at 08:08
  • Please make sure you're launch it on Android 4.3 – Maxim Firsoff Sep 19 '17 at 08:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154765/discussion-between-liem-vo-and-maxim-firsoff). – Liem Vo Sep 19 '17 at 08:26
  • 3
    You can also add padding to icon android:drawablePadding="" – Mirza Asad Mar 20 '18 at 03:10
  • As of API 17, you may want to use android:drawableStart instead of android:drawableLeft to support RTL layouts. (https://developer.android.com/about/versions/android-4.2.html#RTL) – Benjamin Kershner Mar 05 '20 at 00:31
20

To add an image to left, right, top or bottom, you can use attributes like this:

android:drawableLeft
android:drawableRight
android:drawableTop
android:drawableBottom

The sample code is given above. You can also achieve this using relative layout.

Yurii
  • 4,811
  • 7
  • 32
  • 41
user3515854
  • 211
  • 1
  • 4
  • 4
    How Do I do this programatically – Sujay U N May 27 '17 at 19:42
  • 2
    You could say `android:drawableStart` instead of Left, and `android:drawableEnd` instead of Right. – Simão Garcia Nov 07 '18 at 12:06
  • 1
    @SimãoGarcia *should. Start should replace right and end should replace left in all places. This is to ensure that right to left reading as well as left to right reading is available since some other countries read differently. – Carson J. May 22 '19 at 20:18
  • @CarsonJ. that's correct, but you have the directions backwards Replace `left` with `start`, and replace `right` with `end` – Ky - May 14 '21 at 16:02
19

You can use the Material Components Library and the MaterialButton component.
Use the app:icon and app:iconGravity="start" attributes.

Something like:

  <com.google.android.material.button.MaterialButton
        style="@style/Widget.MaterialComponents.Button.Icon"
        app:icon="@drawable/..."
        app:iconGravity="start"
        ../>

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
13

For anyone looking to do this dynamically then setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom) on the buttons object will assist.

Sample

Button search = (Button) findViewById(R.id.yoursearchbutton);
search.setCompoundDrawablesWithIntrinsicBounds('your_drawable',null,null,null);
Sid110307
  • 497
  • 2
  • 8
  • 22
Kennedy Nyaga
  • 3,455
  • 1
  • 26
  • 25
  • 6
    Using setCompoundDrawables didn't reflect on the UI. Used setCompoundDrawablesWithIntrinsicBounds instead, and that worked. – Aldo Jun 29 '18 at 07:24
7

This is what you really want.

<Button
       android:id="@+id/settings"
       android:layout_width="190dp"
       android:layout_height="wrap_content"
       android:layout_gravity="center_horizontal"
       android:background="@color/colorAccent"
       android:drawableStart="@drawable/ic_settings_black_24dp"
       android:paddingStart="40dp"
       android:paddingEnd="40dp"
       android:text="settings"
       android:textColor="#FFF" />
Stackoverflower
  • 292
  • 4
  • 17
3

@Liem Vo's answer is correct if you are using android.widget.Button without any overriding. If you are overriding your theme using MaterialComponents, this will not solve the issue.

So if you are

  1. Using com.google.android.material.button.MaterialButton or
  2. Overriding AppTheme using MaterialComponents

Use app:icon parameter.

<Button
    android:id="@+id/bSearch"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:text="Search"
    android:textSize="24sp"
    app:icon="@android:drawable/ic_menu_search" />
Chamin Wickramarathna
  • 1,672
  • 2
  • 20
  • 34
1

What about like this?

<Button
            android:id="@+id/yourID"
            android:drawableStart="@drawable/ic_flag"
            android:textColor="#FFFFFF"
            android:textSize="12sp"
            android:textStyle="bold"
            android:textAlignment="textStart"
            android:background="@drawable/btn_background"
            android:fontFamily="@font/YourFont"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Your Text" />
Papel
  • 541
  • 4
  • 7
1

try It:-

position-> left,right,top,bottom
  android:drawableposition="@android:drawable/-yourImage-"
  

  android:drawabletop="-Yourfilesrc-"
  android:drawablebottom="-Yourfilesrc-"
  android:drawableleft="-Yourfilesrc-"
  android:drawableright="-Yourfilesrc-"
0

I was experiencing the same problem with pure Button view. In my case XML solution was not usefull, because I have some logic to show/hide this icon.

There is one more solution using pure Kotlin:

(bSearch as? MaterialButton)?.let {
    icon = AppCompatResources.getDrawable(context, R.drawable.search_icon)
    iconGravity = MaterialButton.ICON_GRAVITY_START
}

P.S. We can cast Button to MaterialButton as fair as we can use icon param in Button: icon param is not actually Button param - it is sneaky MaterialButton param somehow working with Buttons.

Egor
  • 279
  • 5
  • 21
0

There is now an easier way to do this, all you have to do is to use a built-in borderless style, and it'll remove the shadow as well

<Button
style="@style/Widget.AppCompat.Button.Borderless.Colored"/>
Joseph Williamson
  • 771
  • 1
  • 6
  • 18
0

Answer from Yandex Praktikum.

<Button
        ...
        android:text="some text"
        android:textColor="@color/black"
        android:textSize="22sp"
        app:icon="@drawable/icon"
        app:iconGravity="textStart"
        app:iconTint="@color/black"
        app:iconPadding="10dp"
        />