How to have Image and Text Center within a Button

Solution 1:

You can fake it by making a more complex layout, but I'm not sure whether it's worth it. Here's something I hacked together:

<?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">
<Button
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:layout_alignTop="@+id/foreground"
    android:layout_alignBottom="@id/foreground"
    android:layout_alignRight="@id/foreground"
    android:layout_alignLeft="@id/foreground"
    android:onClick="clickedMe" />
   <RelativeLayout
        android:id="@id/foreground"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
    <TextView  
        android:id="@+id/button_text"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" 
        android:text="@string/hello" />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@id/button_text"
        android:paddingTop="10dip"
        android:paddingBottom="10dip"
        android:src="@drawable/icon" />
</RelativeLayout>
</RelativeLayout>

There might be a more concise way to do it. I tend to struggle getting RelativeLayout to do what I want sometimes. Note that you need to pay attention to the z-order (Button needs to appear first in the top level RelativeLayout) and you might need to adjust padding to get it to look the way you want.

Solution 2:

Similar to some other approaches, I think a good solution is to extend Button and add the missing functionality by overriding its onLayout method:

public class CenteredIconButton extends Button {
    private static final int LEFT = 0, TOP = 1, RIGHT = 2, BOTTOM = 3;

    // Pre-allocate objects for layout measuring
    private Rect textBounds = new Rect();
    private Rect drawableBounds = new Rect();

    public CenteredIconButton(Context context) {
        this(context, null);
    }

    public CenteredIconButton(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.buttonStyle);
    }

    public CenteredIconButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if (!changed) return;

        final CharSequence text = getText();
        if (!TextUtils.isEmpty(text)) {
            TextPaint textPaint = getPaint();
            textPaint.getTextBounds(text.toString(), 0, text.length(), textBounds);
        } else {
            textBounds.setEmpty();
        }

        final int width = getWidth() - (getPaddingLeft() + getPaddingRight());

        final Drawable[] drawables = getCompoundDrawables();

        if (drawables[LEFT] != null) {
            drawables[LEFT].copyBounds(drawableBounds);
            int leftOffset =
                    (width - (textBounds.width() + drawableBounds.width()) + getRightPaddingOffset()) / 2 - getCompoundDrawablePadding();
            drawableBounds.offset(leftOffset, 0);
            drawables[LEFT].setBounds(drawableBounds);
        }

        if (drawables[RIGHT] != null) {
            drawables[RIGHT].copyBounds(drawableBounds);
            int rightOffset =
                    ((textBounds.width() + drawableBounds.width()) - width + getLeftPaddingOffset()) / 2 + getCompoundDrawablePadding();
            drawableBounds.offset(rightOffset, 0);
            drawables[RIGHT].setBounds(drawableBounds);
        }
    }
}

The sample only works for left and right drawables, but could be extended to adjust top and bottom drawables too.

Solution 3:

How about this one?

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/lovely_color"
    android:clickable="true"
    android:onClick="clickHandler">

       <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="no?"
            android:textColor="@color/white"
            android:layout_centerHorizontal="true"
            android:drawableLeft="@drawable/lovely_icon"
            android:drawablePadding="10dp"
            android:padding="10dp"
            android:gravity="center"
            android:textSize="21sp"/>

</RelativeLayout>

Solution 4:

This should work

<LinearLayout        

android:layout_width="fill_parent"        
android:layout_height="wrap_content" 
android:gravity="center_horizontal">    
<TextView          
    android:id="@+id/button_text"        
    android:layout_width="wrap_content"         
    android:layout_height="wrap_content"        
    android:layout_centerInParent="true"        
     android:text="hello" />    
 <ImageView        
     android:layout_width="wrap_content"        
     android:layout_height="wrap_content"
     android:paddingBottom="10dip"
/>
</LinearLayout>