Android: how to create a button with an image and text that are centered

I am stuck in an unusual problem with Android - I want to have a button that looks like this:

|-----------------------------------------------------------------------| | [icon] <5px> [text text text] | |-----------------------------------------------------------------------| 

and the group ([icon] <5px> [text text to text]) should be centered. Note that 5px is used as a placeholder for any add-on that you want between the icon and the text.

I found here a few answers that more or less gravitated towards setting the background (which I don't want to do because I have a different background) or using the android: drawableLeft property to set the icon.

However, the documentation for the setCompoundDrawablesWithIntrinsicBounds method seems a bit misleading (see here) . It indicates that the image is placed on the left / right / top / bottom side of the TEXT, which is incorrect. The icon is placed on the corresponding side of the BUTTON. For instance:

Setting the android: drawableLeft property puts the icon in the leftmost position and gets me (with gravitational CENTER):

  |-----------------------------------------------------------------------| | [icon] [text text text] | |-----------------------------------------------------------------------| 

or this (with LEFT gravity):

  |-----------------------------------------------------------------------| | [icon] [text text text] | |-----------------------------------------------------------------------| 

Both ugly as hell :(

I found a workaround that looks like this:

 public static void applyTextOffset(Button button, int buttonWidth) { int textWidth = (int) button.getPaint().measureText(button.getText().toString()); int padding = (buttonWidth / 2) - ((textWidth / 2) + Constants.ICON_WIDTH + Constants.ICON_TO_TEXT_PADDING); button.setPadding(padding, 0, 0, 0); button.setCompoundDrawablePadding(-padding); } 

And it works more or less, but I do not find it on my own for the following reasons:

  • This requires knowing the width of the button. With buttons with automatic size, it will not be known until the actual layout is completed. Google recommends using a listener to find out the actual width after rendering, but this makes the code very complicated.
  • It seems to me that I am taking responsibility for the layout from the Android layout engine.

Is there a more elegant solution?

+6
source share
4 answers

To achieve this effect, you can use the following subclass of Button .

  • Paste this class into your project and customize the package name if necessary.
  package com.phillipcalvin.iconbutton; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.Button; public class IconButton extends Button { protected int drawableWidth; protected DrawablePositions drawablePosition; protected int iconPadding; // Cached to prevent allocation during onLayout Rect bounds; private enum DrawablePositions { NONE, LEFT, RIGHT } public IconButton(Context context) { super(context); bounds = new Rect(); } public IconButton(Context context, AttributeSet attrs) { super(context, attrs); bounds = new Rect(); } public IconButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); bounds = new Rect(); } public void setIconPadding(int padding) { iconPadding = padding; requestLayout(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Paint textPaint = getPaint(); String text = getText().toString(); textPaint.getTextBounds(text, 0, text.length(), bounds); int textWidth = bounds.width(); int contentWidth = drawableWidth + iconPadding + textWidth; int contentLeft = (int)((getWidth() / 2.0) - (contentWidth / 2.0)); setCompoundDrawablePadding(-contentLeft + iconPadding); switch (drawablePosition) { case LEFT: setPadding(contentLeft, 0, 0, 0); break; case RIGHT: setPadding(0, 0, contentLeft, 0); break; default: setPadding(0, 0, 0, 0); } } @Override public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom) { super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom); if (null != left) { drawableWidth = left.getIntrinsicWidth(); drawablePosition = DrawablePositions.LEFT; } else if (null != right) { drawableWidth = right.getIntrinsicWidth(); drawablePosition = DrawablePositions.RIGHT; } else { drawablePosition = DrawablePositions.NONE; } requestLayout(); } } 

2. Change your layout to use this new subclass instead of the usual Button :

  <com.phillipcalvin.iconbutton.IconButton android:id="@+id/search" android:layout_width="fill_parent" android:layout_height="wrap_content" android:drawableLeft="@drawable/search" android:text="@string/search" /> 

3. If you want to add padding between the drawing and the text, add the following onCreate to your activity:

  // Anywhere after setContentView(...) IconButton button = (IconButton)findViewById(R.id.search); button.setIconPadding(10); 

This subclass also supports drawableRight . It does not support more than one available.

If you need more features, for example, the ability to specify iconPadding directly in your XML layout, I have a library that supports this.

+10
source

You can also use a custom view to create a custom button.

It can be from simple to extremely complex.

It would be easy if all you have to do is override onDraw() . It will be more difficult if you need to lay out several views.

0
source

Just write Button in LinearLayout. Something like that

  <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@drawable/ic_left" android:drawablePadding="5dp" android:duplicateParentState="true" android:text="Button text"/> </LinearLayout> 
0
source

I tried this in eclipse and did not look for errors:

 <Button android:id="@+id/test" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" > <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:gravity="center" android:background="@android:color/transparent" > </LinearLayout> </Button> 

Therefore, I assume that you could add images and textual representations to the layout itself inside the button and center the layout.

Sincerely.

-3
source

Source: https://habr.com/ru/post/912189/


All Articles