12

I would like to have an image set to background a text on it and an icon on the left side of the text. Very easy in iPhone, but can't figure out how to do it at Android, to be resizable that button and keep the icon + text position and distance properly.

iPhone:

iPhone

Android I have this:

Android

The xml code is:

<Button
    android:id="@+id/btSettings"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@id/tvWhatever"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="20dp"
    android:background="@drawable/bt_general"
    android:drawableTop="@drawable/settings_selected"
    android:text="@string/settings"
    android:textColor="#000000" />

Took the code from here.

If I use android:drawableLeft , than the icon will go to most left part.

enter image description here

If I start playing with semi hardcoded paddings, than I will have different look at diff devives: ( phone and table)

If I add the android:gravity="left|center_vertical" than it will look like this:

enter image description here

The text is variable: it will change, when the user change the language.

How to do it properly?

I don't want to downvote anybody's answer, but please read the question and don't suggest what I have tryed already. Also told the hardcoded fixes doesn't work well.

This is not a homework, but a commercial software part.

Here is a suggested code from answers:

<RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bt_general"
        android:padding="20dip" >

        <ImageView
            android:id="@+id/xIcon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10dip"
            android:src="@drawable/settings_selected" />

        <TextView
            android:id="@+id/xSettingsTxt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@string/settings"
            android:textColor="#000000" />
    </RelativeLayout>

What do you think how it will look like the android:layout_marginLeft="10dip" on Galaxy s4? Here is a preview:

enter image description here

This is not, what I have asked. "dip" or "dp" or "px" shouldn't be used anywhere as distance from left, top, because phones has HPDI, smaller screen and Tablets has MDPI and wide resolutions. Simple doesn't work on mdpi, and xxhdpi.

Nizam answer is very close to a good solution:

enter image description here

Community
  • 1
  • 1
  • Have you tried, **android:drawablePadding** – Piyush Oct 02 '13 at 09:13
  • @PiyushGupta that need a dimension, not a drwable: Caused by: java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x3 –  Oct 02 '13 at 09:16
  • @matheszabi Check the layout that i put in my edit part, that will work. –  Oct 02 '13 at 10:06

14 Answers14

11

Maybe you should use RelativeLayout with rounded corners, than put TextView and ImageView inside of it.

subasa
  • 289
  • 2
  • 13
  • This was the first correct answer. Others gave code, when this already upvoted. Some code aren't working as expencted, but based on idea I can make this. Far not as simple than in iPhone side. I will suggest to my client to drop the icon from Android buttons or I have to work more to look and feel properly on all devices that elment –  Oct 02 '13 at 10:08
3

Try this:

    Button button = (Button) findViewById(R.id.button1);
    Spannable buttonLabel = new SpannableString(" Settings");
    buttonLabel.setSpan(new ImageSpan(getApplicationContext(), R.drawable.settings_selected,      
        ImageSpan.ALIGN_BOTTOM), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    button.setText(buttonLabel);
Nizam
  • 5,698
  • 9
  • 45
  • 57
  • +1, very close to a good solution: the Text is a bit to low vs the image and ImageSpan.ALIGN_BASELINE constraint doesn't work either. From text is missing the first letter, if the first space is omited, I think need a gap there –  Oct 02 '13 at 17:17
  • actually this is an Android OS bug for ALIGN_BASELINE doesn't work and has a workaround –  Oct 02 '13 at 19:21
3

Try this: Follow this : http://porcupineprogrammer.blogspot.in/2013/03/android-ui-struggles-making-button-with.html

<FrameLayout
    style="?android:attr/buttonStyle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:drawableLeft="@android:drawable/ic_delete"
        android:gravity="center"
        android:text="Button Challenge" />
</FrameLayout>
Amit Prajapati
  • 13,525
  • 8
  • 62
  • 84
1

Try below layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="100dip"
android:orientation="horizontal"
android:background="@drawable/round_corners_drawable" >

<ImageView 
    android:id="@+id/xIcon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_marginLeft="10dip"
    android:layout_centerVertical="true"
    android:src="@drawable/ic_launcher"/>

<TextView
    android:id="@+id/xSettingsTxt"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Settings"
    android:layout_centerInParent="true" />

</RelativeLayout>

and drawable/round_corner_drawable is as below:

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >

<solid android:color="#310704"/>

<corners
    android:bottomRightRadius="20sp"
    android:bottomLeftRadius="20sp"
    android:topLeftRadius="20sp"
    android:topRightRadius="20sp"/>

<gradient
    android:startColor="#99310704"
    android:centerColor="#99310704"
    android:endColor="#99310704"
    android:angle="270" />

</shape>

Also, if you want to use your image as a background, give android:layout_height="wrap_content" and set it as a background for relative layout.

p.s. If you put different color values for startColor, centerColor and endColor, you will get that gradient effect for your background drawable. So change the color values accordingly.

EDIT:

Try below layout, i edited it to fit in different screen sizes with rounded corner drawable.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dip"
android:background="@drawable/dialog_round_corners" >

<ImageView 
    android:id="@+id/xIcon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toLeftOf="@+id/xSettingsTxt"
    android:layout_centerVertical="true"
    android:src="@drawable/ic_launcher"/>

<TextView
    android:id="@+id/xSettingsTxt"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Settings"
    android:layout_centerInParent="true" />

</RelativeLayout>
  • with those semi hardcoded fixes I have problem: android:layout_height="100dip" those are looking bad if you set for a HDPI small screen phone. Eg Nexus one and will check at MDPI large screen , low resolution tablet –  Oct 02 '13 at 09:41
  • That is true, but thats why I specified, if you have different sized images for hdpi, mdpi, xhdpi and ldpi, you can set your image as a background for RelativeLayout and set the height as wrap_content. –  Oct 02 '13 at 09:43
  • upvoted for your effort, but this solution will not fit my needs –  Oct 02 '13 at 09:49
1

Here is how i do things :

LAYERS

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:drawable="@drawable/rounded_border"/>
    <item android:drawable="@drawable/selector_button"/>

</layer-list>

SELECTOR

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@color/clr_grey_1" android:state_selected="true" android:state_window_focused="false"/>
    <item android:drawable="@color/clr_grey_1" android:state_selected="true"/>
    <item android:drawable="@color/clr_grey_1" android:state_pressed="true" android:state_selected="false"/>
    <item android:drawable="@color/clr_main_green" android:state_selected="false"/>

</selector>

ROUNDED CORNER

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

    <solid android:color="@color/clr_grey_2" />

    <stroke
        android:width="1dp"
        android:color="@android:color/white" />

    <corners
        android:bottomLeftRadius="8dp"
        android:bottomRightRadius="8dp"
        android:topLeftRadius="8dp"
        android:topRightRadius="8dp" />

    <padding
        android:bottom="0dp"
        android:left="4dp"
        android:right="0dp"
        android:top="4dp" />

</shape>

Use this on relative layout, with an imageview and button inside it

An-droid
  • 6,433
  • 9
  • 48
  • 93
  • this has no text element –  Oct 02 '13 at 10:06
  • I didn't write it in the post, you can use the LAYERS in a RelativeLayout as background and inside the layout just position the elements you wanna use ;) – An-droid Oct 02 '13 at 10:15
1
<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button Text"
    android:background="@drawable/round_background"
    android:drawableLeft="@drawable/icon"/>

save the xml code below as round_background.xml and put it on drawable folder. use this if you want, but you can also use image from the drawable folder.

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

    <solid android:color="#f5f5f5" />

    <corners android:radius="10px" />

    <padding
        android:bottom="0dp"
        android:left="0dp"
        android:right="0dp"
        android:top="0dp" />

    <stroke
        android:width="1dp"
        android:color="#ccc" />

</shape>
jofftiquez
  • 7,548
  • 10
  • 67
  • 121
1

I had achieved that with following code. May be used as an easier alternative to above solutions.

<Button android:id="@+id/btnUserProfile"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:drawableLeft="@drawable/ic_user_profile"
    android:background="#6C6C6C"
    android:drawablePadding="8dp"
    android:gravity="left|center_vertical"          
    android:text="@string/my_profile"
    android:textStyle="bold|italic" />   

the button view is marked in red(this is not a list item but a button with above code):

enter image description here

Dexter
  • 4,036
  • 3
  • 47
  • 55
1

Found a class called CenteredIconButton that extends Button at this link. Worked like magic. How to have Image and Text Center within a Button . Thanks to @atomicode

Community
  • 1
  • 1
Visionwriter
  • 649
  • 6
  • 12
1

If your button width: android:layout_width="wrap_content" then your code will be like this:

 <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawableLeft="@drawable/img name"
        android:gravity="left|center"
        android:text="Button" />

Else if your button width: android:layout_width="match_parent" then your code will be like this:

<Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawableLeft="@drawable/img name"
        android:gravity="left|center"
        android:text="Button"
        android:paddingLeft="100dp" 
        />

By the way android:paddingLeft="100dp", change 100 with your suitable value.

spenibus
  • 4,339
  • 11
  • 26
  • 35
Ahmed Soliman
  • 416
  • 5
  • 11
0

Try to use TextView,

<TextView
    android:id="@+id/txtSettings"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@id/tvWhatever"
    android:layout_centerHorizontal="true"
    android:text="@string/settings"
    android:textColor="#000000" />

In Java

txtView.setBackgroundResources(R.drawable.bt_general);
txtView.setCompoundDrawablesWithIntrinsicBounds(Drawable left,Drawable top,Drawable right,Drawable bottom);

where Drawable image is,

Bitmap bitmap= BitmapFactory.decodeResource(context.getResources(), 
    R.drawable.settings_selected);
BitmapDrawable drawable=new BitmapDrawable(getResources(), bitmap);
No_Rulz
  • 2,679
  • 1
  • 20
  • 33
  • my background is a drawable: a png file. The yellow icon is another png. The text is changing according to translation where to put my icon? to left or top? –  Oct 02 '13 at 09:44
  • put your yellow icon in left. And set your background image to Textview as android:background="..." – No_Rulz Oct 02 '13 at 09:46
  • that is equivalent with android:drawableLeft –  Oct 02 '13 at 10:14
  • I have checked this solution too: it is equivalent with android:drawableLeft, by far not what is expected –  Oct 02 '13 at 17:40
0
<Button
    android:id="@+id/btSettings"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/back_button"
    android:drawablePadding="5dp"
    android:drawableLeft="@drawable/ic_launcher"
    android:text="Settings"
    android:padding="20dp"
    android:textColor="#000000" />

You can use paddingLeft and paddingRight to get button as the one in iphone

Piyush
  • 2,040
  • 16
  • 14
  • "If I use android:drawableLeft , than the icon will go to most left part." it will look like presented above: total left, I need on Center –  Oct 02 '13 at 09:51
0

I just implemented this kind of button (and it has been deployed in a large scale app), it is not really complicated : content of large_button.xml :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/large_button_background"
    android:clickable="true"
    android:gravity="center_horizontal"
    android:orientation="horizontal" >

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="center_vertical"
        android:layout_marginRight="16dp"
        android:src="@drawable/some_icon" />

    <com.my.app.widget.RobotoTextView
        android:id="@+id/large_button_text"
        style="@style/AppName_RobotoBold"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:ellipsize="end"
        android:focusable="false"
        android:gravity="center_vertical"
        android:maxLines="1"
        android:singleLine="true"
        android:textColor="@color/text_main"
        />

</LinearLayout>

Then, to use it I just have to use the include tag :

<include
    android:id="@+id/large_button"
    android:layout_width="match_parent"
    android:layout_height="@dimen/large_button_height"
    android:layout_marginBottom="@dimen/large_button_vertical_margin"
    android:layout_marginLeft="@dimen/large_button_horizontal_margin"
    android:layout_marginRight="@dimen/large_button_horizontal_margin"
    android:layout_marginTop="@dimen/large_button_vertical_margin"
    layout="@layout/large_button" />

large_button_background is a selector that points to the different drawables to use for each button state

I used a LinearLayout, it allows to simply center both text & icons in the button. It should also be doable with a GridLayout. If you want to center just on the text (I don't think it looks great though but that's your choice), use a RelativeLayout.

Teovald
  • 4,369
  • 4
  • 26
  • 45
0

You can use android:paddingLeft, android:paddingRight and layout_width at a fixed width to solve the issue.

<Button
android:id="@+id/btSettings"
android:layout_width="148dp"
android:layout_height="wrap_content"
android:paddingLeft="32dp"
android:paddingRight="32dp"
android:background="@drawable/bt_general"
android:drawableLeft="@drawable/settings_selected"
android:text="@string/settings"
android:textColor="#000000"/>  
Jason Huh
  • 147
  • 2
  • 2