Android:如何创建一个按钮,图像和文本都居中

vap*_*p78 6 layout android text image button

我陷入了Android的一个奇怪问题 - 我希望有一个看起来像这样的按钮:

 |-----------------------------------------------------------------------|
 |                   [icon] <5px> [text text text]                       |
 |-----------------------------------------------------------------------|
Run Code Online (Sandbox Code Playgroud)

并且组([icon] <5px> [文本文本文本])应居中.请注意,5px仅用作占位符,用于图标和文本之间的任何填充

我在这里找到了一些答案或多或少地围绕设置背景(我不想做因为我有另一个背景)或使用android:drawableLeft属性来设置图标.

但是看起来像setCompoundDrawablesWithIntrinsicBounds方法的文档有点误导(见这里).它声明图像位于TEXT的左/右/上/下侧,这是不正确的.图标位于按钮的相应侧.例如:

设置android:drawableLeft属性将图标放在最左边的位置并获取此信息(使用重力CENTER):

 |-----------------------------------------------------------------------|
 | [icon]                     [text text text]                           |
 |-----------------------------------------------------------------------|
Run Code Online (Sandbox Code Playgroud)

或者这个(重力为左):

 |-----------------------------------------------------------------------|
 | [icon] [text text text]                                               |
 |-----------------------------------------------------------------------|
Run Code Online (Sandbox Code Playgroud)

两个都是丑陋的地狱:(

我找到了一个看起来像这样的解决方法:

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);
}
Run Code Online (Sandbox Code Playgroud)

它或多或少有效,但由于以下原因,我不喜欢它:

  • 它需要知道按钮宽度.使用自动调整大小的按钮,直到实际布局完成后才能知道.Google建议在渲染完成后使用侦听器来学习实际宽度,但这会使代码变得非常复杂.
  • 我觉得我正在接受Android布局引擎的布局责任

难道没有更优雅的解决方案吗?

Phi*_*vin 10

您可以使用以下Button子类来实现此效果.

  1. 将此类粘贴到项目中,并根据需要调整包名称.
    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();
      }
    }
Run Code Online (Sandbox Code Playgroud)

2.修改布局以使用此新子类而不是plain 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" />
Run Code Online (Sandbox Code Playgroud)

3.如果要在drawable和text之间添加填充,请将以下内容添加到您的活动中onCreate:

    // Anywhere after setContentView(...)
    IconButton button = (IconButton)findViewById(R.id.search);
    button.setIconPadding(10);
Run Code Online (Sandbox Code Playgroud)

该子类也支持drawableRight.它不支持多个drawable.

如果您想要更多功能,例如能够iconPadding直接在布局XML中指定,我有一个支持它库.