Android: как создать кнопку с изображением и текстом по центру - PullRequest
6 голосов
/ 02 апреля 2012

Я застрял в странной проблеме с Android - мне нужна кнопка, которая выглядит следующим образом:

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

и группа ([icon] <5px> [text text text]) должнабыть в центре.Обратите внимание, что 5px используется просто как заполнитель для любого отступа между значком и текстом

Я нашел здесь несколько ответов, которые более или менее тяготеют к установке фона (чего я не делаю)хочу сделать, потому что у меня есть другой фон) или использовать свойство android: drawableLeft для установки значка.

Однако похоже, что документация метода setCompoundDrawablesWithIntrinsicBounds немного вводит в заблуждение (см. здесь) ,В нем говорится, что изображение размещено слева / справа / сверху / снизу от текста, что не соответствует действительности.Значок находится на соответствующей стороне кнопки.Например:

Установка свойства android: drawableLeft помещает значок в крайнее левое положение и возвращает мне это (с гравитационным центром):

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

или это (с гравитацией влево):

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

Оба ужасны как ад: (

Я нашел обходной путь, который выглядит так:

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);
}

И это работает более или менее, но я неМне это не нравится по следующим причинам:

  • требуется знать ширину кнопки. С кнопками авторазмера это не будет известно, пока не будет готов фактический макет. Google рекомендует использовать слушатель дляузнать реальную ширину после рендеринга, но это очень усложняет код.
  • Мне кажется, что я беру на себя ответственность за макет из движка Android-макета

Неесть более элегантное решение?

Ответы [ 4 ]

10 голосов
/ 04 января 2013

Вы можете использовать следующий подкласс 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();
      }
    }

2.Измените свой макет, чтобы использовать этот новый подкласс вместо простого 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.Если вы хотите добавить отступ между отрисовкой и текстом, добавьте следующее к onCreate вашей деятельности:

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

Этот подкласс также поддерживает drawableRight.Он не поддерживает более одного рисования.

Если вам нужны дополнительные функции, такие как возможность указания iconPadding непосредственно в XML макета, у меня есть библиотека , которая поддерживает это.

0 голосов
/ 03 августа 2015

Простой способ - написать Button в LinearLayout. Как то так

 <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 голосов
/ 02 апреля 2012

Вы можете также рассмотреть возможность использования настраиваемого представления для создания настраиваемой кнопки.

Это может быть где угодно от простого до чрезвычайно сложного.

Было бы легко, если бы все, что вам нужно сделать, этопереопределить onDraw().Будет сложнее, если вам нужно выложить несколько видов.

0 голосов
/ 02 апреля 2012

Я попробовал это в затмении, и оно не выдало ошибок:

<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>

Поэтому, я полагаю, вы можете добавить изображения и текстовые представления в макет, сам внутри кнопки, и центрировать макет.

С уважением.

...