Как центрировать значок и текст в кнопке Android с шириной «заполнить родительский элемент»


118

Я хочу иметь кнопку Android со значком + текстом по центру внутри нее. Я использую атрибут drawableLeft для установки изображения, это хорошо работает, если кнопка имеет ширину, "wrap_content"но мне нужно растянуть до максимальной ширины, поэтому я использую ширину "fill_parent". Это перемещает мой значок прямо влево от кнопки, и я хочу, чтобы и значок, и текст располагались по центру внутри кнопки.

Я пытался настроить отступы, но это позволяет указать только фиксированное значение, поэтому мне это не нужно. Мне нужно, чтобы значок + текст был выровнен по центру.

<Button 
    android:id="@+id/startTelemoteButton" 
    android:text="@string/start_telemote"
    android:drawableLeft="@drawable/start"
    android:paddingLeft="20dip"
    android:paddingRight="20dip"            
    android:width="fill_parent"
    android:heigh="wrap_content" />

Есть предложения о том, как я могу этого добиться?


Возможно, для этого нет простого решения? Надо ли пробовать с 9patch button img со значком внутри?
jloriente 03

Это могло бы быть решением. Будет ли текст кнопки локализован или статичен?
Октавиан А. Дамиан

Это локализовано. Другого решения для этого нет? Мне удалось это сделать с патчем 9, но возникли проблемы при смене локали.
jloriente

Как насчет использования кнопки с выдвижным верхом и добавления к ней отступов?
Francesco

плохой дизайн фреймворка
Мухаммад Бабар

Ответы:


75

android: drawableLeft всегда сохраняет android: paddingLeft как расстояние от левой границы. Если для кнопки не задано значение android: width = "wrap_content", она всегда будет висеть слева!

В Android 4.0 (уровень API 14) вы можете использовать атрибут android: drawableStart, чтобы поместить объект для рисования в начало текста. Единственное решение с обратной совместимостью, которое я придумал, - это использование ImageSpan для создания Spannable Text + Image:

Button button = (Button) findViewById(R.id.button);
Spannable buttonLabel = new SpannableString(" Button Text");
buttonLabel.setSpan(new ImageSpan(getApplicationContext(), R.drawable.icon,      
    ImageSpan.ALIGN_BOTTOM), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
button.setText(buttonLabel);

В моем случае мне также нужно было настроить атрибут android: gravity кнопки, чтобы он выглядел по центру:

<Button
  android:id="@+id/button"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:minHeight="32dp"
  android:minWidth="150dp"
  android:gravity="center_horizontal|top" />

Ницца. Последняя строка должна бытьbutton.setText(buttonLabel)
AlexD

1
Unicode имеет обширный набор значков символов, совместимых со строками в Android. Если вы можете найти приемлемый вариант, это простое решение, и у него есть дополнительный бонус в виде масштабирования с размером текста. Например, у него есть конверт для значка электронной почты и пара разных телефонов для кнопки вызова.
GLee

1
Я не понимаю, как это сработало для кого-то, для меня он рисует 2 значка ... один слева и один прямо в центре, который отображается поверх текста.
Джастин

11
drawableStart не будет работать. См. Этот поток: stackoverflow.com/questions/15350990/… Также кажется, что когда вы устанавливаете текст с помощью spannable, стиль игнорируется.
Dapp 06

11
drawableStart не работает, и он был добавлен в API уровня 17 для поддержки RTL
Сильвия Х,

35

Я знаю, что опаздываю с ответом на этот вопрос, но мне это помогло:

<FrameLayout
            android:layout_width="match_parent"
            android:layout_height="35dp"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="10dp"
            android:background="@color/fb" >

            <Button
                android:id="@+id/fbLogin"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:background="@null"
                android:drawableLeft="@drawable/ic_facebook"
                android:gravity="center"
                android:minHeight="0dp"
                android:minWidth="0dp"
                android:text="FACEBOOK"
                android:textColor="@android:color/white" />
        </FrameLayout>

Я нашел это решение отсюда: проблемы с пользовательским интерфейсом Android: создание кнопки с центрированным текстом и значком

введите описание изображения здесь


6
Проблема в том, что ширина кнопки не соответствует ширине макета рамки.
Clive Jefferies

30

Все предыдущие ответы кажутся устаревшими

Вы можете использовать MaterialButtonтеперь, который позволяет установить гравитацию значка.

 <com.google.android.material.button.MaterialButton
        android:id="@+id/btnDownloadPdf"
        android:layout_width="0dp"
        android:layout_height="56dp"
        android:layout_margin="16dp"
        android:gravity="center"
        android:textAllCaps="true"
        app:backgroundTint="#fc0"
        app:icon="@drawable/ic_pdf"
        app:iconGravity="textStart"
        app:iconPadding="10dp"
        app:iconTint="#f00"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:text="Download Pdf" />

введите описание изображения здесь

Очевидно, что для использования компонентов материала вам потребуется:

Добавить зависимость implementation 'com.google.android.material:material:1.3.0-alpha01'(использовать последнюю версию)

Сделайте вашу тему расширенной темой Material Components

<style name="AppTheme" parent="Theme.MaterialComponents.Light">
...
</style>

Если вы не можете этого сделать, расширьте его из темы Material Bridge.

<style name="AppTheme" parent="Theme.MaterialComponents.Light.Bridge">
...
</style>

Спасибо! Ты спас мне день! Работает нормально
Black_Zerg 01

29

Я использовал LinearLayout вместо Button . OnClickListener , что мне нужно использовать хорошо работает и для LinearLayout.

<LinearLayout
    android:id="@+id/my_button"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/selector"
    android:gravity="center"
    android:orientation="horizontal"
    android:clickable="true">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="15dp"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:src="@drawable/icon" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Text" />

</LinearLayout>

9

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

<Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/btn_facebookact_like"
            android:text="@string/btn_facebookact_like"
            android:textColor="@color/black"
            android:textAllCaps="false"
            android:background="@color/white"
            android:drawableStart="@drawable/like"
            android:drawableLeft="@drawable/like"
            android:gravity="center"
            android:layout_gravity="center"
            android:paddingLeft="40dp"
            android:paddingRight="40dp"
            />

PaddingLeft и paddingRight помогли мне с центрированием. голосование за простое решение.
Arrie

2
Как вы справляетесь с тем, что ваша ширина динамична? Если повернуть экран, все значки не будут по центру, верно? На самом деле я столкнулся с этой проблемой
Jacks

это лучший ответ!
Доди Рахмат Викаксоно,

8

Недавно я столкнулся с той же проблемой. Пытался найти более дешевое решение, поэтому придумал это.

   <LinearLayout
        android:id="@+id/linearButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/selector_button_translucent_ab_color"
        android:clickable="true"
        android:descendantFocusability="blocksDescendants"
        android:gravity="center"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@string/app_name"
            android:src="@drawable/ic_launcher" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/app_name"
            android:textColor="@android:color/white" />
    </LinearLayout>

Тогда просто позвонить OnClickListenerна LinearLayout.

Надеюсь, это кому-то поможет, так как это кажется очень распространенной проблемой. :)


1
Это хорошая идея, но плохое решение. Вы можете добиться того же самого с помощью всего одного TextView, используя атрибут drawableLeft. Это позволяет вам просматривать объекты слева от текста.
muetzenflo

@muetzenflo Ага, верно. но когда вы заставляете textView соответствовать родительской ширине, ваш чертеж перемещается в крайнее левое положение, даже если вы центрируете свой текст. дайте мне знать, если я ошибаюсь. и вопрос только об этом.
Анкит Попли

ах, извините .. Я пришел сюда именно из-за этой проблемы и потерял фокус после того, как попробовал слишком много вещей :) Думаю, я не видел леса за деревьями. Моя вина!
muetzenflo

7

Вы можете использовать настраиваемую кнопку, которая измеряет и рисует себя, чтобы разместить левую кнопку мыши. Вы можете найти пример и использование здесь

public class DrawableAlignedButton extends Button {

    public DrawableAlignedButton(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public DrawableAlignedButton(Context context) {
    super(context);
}

public DrawableAlignedButton(Context context, AttributeSet attrs, int style) {
    super(context, attrs, style);
}

private Drawable mLeftDrawable;

@Override
    //Overriden to work only with a left drawable.
public void setCompoundDrawablesWithIntrinsicBounds(Drawable left,
        Drawable top, Drawable right, Drawable bottom) {
    if(left == null) return;
    left.setBounds(0, 0, left.getIntrinsicWidth(), left.getIntrinsicHeight());
    mLeftDrawable = left;
}

@Override
protected void onDraw(Canvas canvas) {
    //transform the canvas so we can draw both image and text at center.
    canvas.save();
    canvas.translate(2+mLeftDrawable.getIntrinsicWidth()/2, 0);
    super.onDraw(canvas);
    canvas.restore();
    canvas.save();
    int widthOfText = (int)getPaint().measureText(getText().toString());
    int left = (getWidth()+widthOfText)/2 - mLeftDrawable.getIntrinsicWidth() - 2;
    canvas.translate(left, (getHeight()-mLeftDrawable.getIntrinsicHeight())/2);
    mLeftDrawable.draw(canvas);
    canvas.restore();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int height = getMeasuredHeight();
    height = Math.max(height, mLeftDrawable.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom());
    setMeasuredDimension(getMeasuredWidth(), height);
}
}

использование

<com.mypackage.DrawableAlignedButton
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:drawableLeft="@drawable/my_drawable"
        android:gravity="center"
        android:padding="7dp"
        android:text="My Text" />

Вы можете включить код в свой ответ, что должно быть предпочтительным способом (если он не слишком длинный), так как ссылки могут со временем исчезнуть-
Лукас Кнут,

2
Не очень точно, но я так понимаю
Алексей Семенюк

Он сдвигает текст вправо, но недостаточно (изображение перекрывает текст). Кроме того, как и другие решения для пользовательских представлений, он не принимает длинный текст правильно.
CoolMind

5

Это мое решение, которое я написал 3 года назад. Кнопка имеет текст и левый значок и находится в рамке, которая является настоящей кнопкой здесь и может быть растянута с помощью fill_parent. Я не могу проверить это снова, но тогда он работал. Вероятно, Button не нужно использовать, и ее можно заменить на TextView, но я не буду тестировать ее прямо сейчас, и здесь она не сильно меняет функциональность.

<FrameLayout
    android:id="@+id/login_button_login"
    android:background="@drawable/apptheme_btn_default_holo_dark"
    android:layout_width="fill_parent"
    android:layout_gravity="center"
    android:layout_height="40dp">
    <Button
        android:clickable="false"
        android:drawablePadding="15dp"
        android:layout_gravity="center"
        style="@style/WhiteText.Small.Bold"
        android:drawableLeft="@drawable/lock"
        android:background="@color/transparent"
        android:text="LOGIN" />
</FrameLayout>

1
Теперь я вижу, что не я один был с этим решением :)
Ренетик

4

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

Создайте RelativeLayout «wrap_content» с изображением кнопки в качестве фона или самой кнопкой в ​​качестве первого элемента макета. Получите LinearLayout и установите для него layout_centerInParent и wrap_content. Затем установите Drawable как Imageview. Наконец, установите TextView с вашим текстом (языковой стандарт).

так что в основном у вас есть эта структура:

RelativeLayout
  Button
    LinearLayout
      ImageView
      TextView

или вот так:

RelativeLayout with "android-specific" button image as background
  LinearLayout
    ImageView
    TextView

Я знаю, что в этом решении есть много элементов, с которыми нужно иметь дело, но с его помощью вы можете очень легко создать свою собственную кнопку, а также установить точное положение текста и чертежей :)


Такой подход может хорошо работать. В моем случае все, что мне было нужно, это RelativeLayout, содержащий TextView. RelativeLayout получает фон, TextView получает значок drawableLeft. Затем в коде: прикрепите onClickListener к RelativeLayout и найдитеViewById для TextView отдельно, если необходимо
Стэн Курдзил,

Первая предложенная структура дает исключение «Кнопка не может быть преобразована в ViewGroup».
Ёнджэ 01

4

Мой способ решения этой проблемы заключался в окружении кнопки легкими <View ../>элементами, размер которых изменяется динамически. Ниже приведены несколько примеров того, чего можно достичь с помощью этого:

Демо от Dev-iL

Обратите внимание, что интерактивная область кнопок в примере 3 такая же, как и в примере 2 (то есть с пробелами), что отличается от примера 4, где между ними нет «неактивных» промежутков.

Код:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="Example 1: Button with a background color:"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="20dp"
            android:paddingEnd="20dp"
            android:layout_weight="0.3"/>
        <!-- Play around with the above 3 values to modify the clickable 
             area and image alignment with respect to text -->
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
    </LinearLayout>

    <TextView
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="Example 2: Button group + transparent layout + spacers:"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
    </LinearLayout>

    <TextView
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="Example 3: Button group + colored layout:"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/darker_gray">
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
    </LinearLayout>

    <TextView
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="Example 4 (reference): Button group + no spacers:"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/darker_gray">
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>   
    </LinearLayout>
</LinearLayout>


2

Вы можете создать собственный виджет:

Класс Java IButton:

public class IButton extends RelativeLayout {

private RelativeLayout layout;
private ImageView image;
private TextView text;

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

public IButton(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

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

    LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.ibutton, this, true);

    layout = (RelativeLayout) view.findViewById(R.id.btn_layout);

    image = (ImageView) view.findViewById(R.id.btn_icon);
    text = (TextView) view.findViewById(R.id.btn_text);

    if (attrs != null) {
        TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.IButtonStyle);

        Drawable drawable = attributes.getDrawable(R.styleable.IButtonStyle_button_icon);
        if(drawable != null) {
            image.setImageDrawable(drawable);
        }

        String str = attributes.getString(R.styleable.IButtonStyle_button_text);
        text.setText(str);

        attributes.recycle();
    }

}

@Override
public void setOnClickListener(final OnClickListener l) {
    super.setOnClickListener(l);
    layout.setOnClickListener(l);
}

public void setDrawable(int resId) {
    image.setImageResource(resId);
}

}

Макет ibutton.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/btn_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" >

<ImageView
    android:id="@+id/btn_icon"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_marginRight="2dp"
    android:layout_toLeftOf="@+id/btn_text"
    android:duplicateParentState="true" />

<TextView
    android:id="@+id/btn_text"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_centerInParent="true"
    android:duplicateParentState="true"
    android:gravity="center_vertical"
    android:textColor="#000000" />
</RelativeLayout>

Чтобы использовать этот настраиваемый виджет:

<com.test.android.widgets.IButton
     android:id="@+id/new"
     android:layout_width="fill_parent"         
     android:layout_height="@dimen/button_height"
     ibutton:button_text="@string/btn_new"
     ibutton:button_icon="@drawable/ic_action_new" />

Вы должны предоставить пространство имен для настраиваемых атрибутов xmlns: ibutton = "http://schemas.android.com/apk/res/com.test.android.xxx", где com.test.android.xxx - корневой пакет приложение.

Просто поместите его под xmlns: android = "http://schemas.android.com/apk/res/android".

Последнее, что вам понадобится, это настраиваемые атрибуты в attrs.xml.

В attrs.xml

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

    <declare-styleable name="IButtonStyle">
        <attr name="button_text" />
        <attr name="button_icon" format="integer" />
    </declare-styleable>

    <attr name="button_text" />

</resources>

Для лучшего позиционирования оберните настраиваемую кнопку внутри LinearLayout, если вы хотите избежать потенциальных проблем с позиционированием RelativeLayout.

Наслаждайтесь!


2

Была аналогичная проблема, но хотелось иметь возможность рисования по центру без текста и без обернутых макетов. Решением было создать настраиваемую кнопку и добавить еще одну возможность рисования в дополнение к LEFT, RIGHT, TOP, BOTTOM. Можно легко изменить место размещения, которое можно рисовать, и расположить его в желаемом положении относительно текста.

CenterDrawableButton.java

public class CenterDrawableButton extends Button {
    private Drawable mDrawableCenter;

    public CenterDrawableButton(Context context) {
        super(context);
        init(context, null);
    }

    public CenterDrawableButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public CenterDrawableButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CenterDrawableButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }


    private void init(Context context, AttributeSet attrs){
        //if (isInEditMode()) return;
        if(attrs!=null){
            TypedArray a = context.getTheme().obtainStyledAttributes(
                    attrs, R.styleable.CenterDrawableButton, 0, 0);

            try {
                setCenterDrawable(a.getDrawable(R.styleable.CenterDrawableButton_drawableCenter));

            } finally {
                a.recycle();
            }

        }
    }

    public void setCenterDrawable(int center) {
        if(center==0){
            setCenterDrawable(null);
        }else
        setCenterDrawable(getContext().getResources().getDrawable(center));
    }
    public void setCenterDrawable(@Nullable Drawable center) {
        int[] state;
        state = getDrawableState();
        if (center != null) {
            center.setState(state);
            center.setBounds(0, 0, center.getIntrinsicWidth(), center.getIntrinsicHeight());
            center.setCallback(this);
        }
        mDrawableCenter = center;
        invalidate();
        requestLayout();
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if(mDrawableCenter!=null) {
            setMeasuredDimension(Math.max(getMeasuredWidth(), mDrawableCenter.getIntrinsicWidth()),
                    Math.max(getMeasuredHeight(), mDrawableCenter.getIntrinsicHeight()));
        }
    }
    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        if (mDrawableCenter != null) {
            int[] state = getDrawableState();
            mDrawableCenter.setState(state);
            mDrawableCenter.setBounds(0, 0, mDrawableCenter.getIntrinsicWidth(),
                    mDrawableCenter.getIntrinsicHeight());
        }
        invalidate();
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        super.onDraw(canvas);

        if (mDrawableCenter != null) {
            Rect rect = mDrawableCenter.getBounds();
            canvas.save();
            canvas.translate(getWidth() / 2 - rect.right / 2, getHeight() / 2 - rect.bottom / 2);
            mDrawableCenter.draw(canvas);
            canvas.restore();
        }
    }
}

attrs.xml

<resources>
    <attr name="drawableCenter" format="reference"/>
    <declare-styleable name="CenterDrawableButton">
        <attr name="drawableCenter"/>
    </declare-styleable>
</resources>

использование

<com.virtoos.android.view.custom.CenterDrawableButton
            android:id="@id/centerDrawableButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:drawableCenter="@android:drawable/ic_menu_info_details"/>

Спасибо! Это то, что я искал.
MistaGreen

Не могли бы вы помочь мне в этом вопросе, stackoverflow.com/questions/35912539/… , с вашим ответом я очень близок к нему, но появляются два
чертежа

Это решение размещает возможность рисования в центре кнопки, чуть выше центрированного текста.
CoolMind

1
<style name="captionOnly">
    <item name="android:background">@null</item>
    <item name="android:clickable">false</item>
    <item name="android:focusable">false</item>
    <item name="android:minHeight">0dp</item>
    <item name="android:minWidth">0dp</item>
</style>

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

    <Button
       style="@style/captionOnly"
       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>

Поместите FrameLayout в LinearLayout и установите ориентацию по горизонтали.


1

Вы можете поместить кнопку над LinearLayout

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/activity_login_fb_height"
        android:background="@mipmap/bg_btn_fb">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/lblLoginFb"
                android:textColor="@color/white"
                android:drawableLeft="@mipmap/icon_fb"
                android:textSize="@dimen/activity_login_fb_textSize"
                android:text="Login with Facebook"
                android:gravity="center" />
        </LinearLayout>
        <Button
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/btnLoginFb"
            android:background="@color/transparent"
            />
    </RelativeLayout>

0

Что произойдет, если вы попробуете android: gravity = "center_horizontal"?


5
Не работает. Текст немного центрирован, но drawableLeft придерживается левой стороны.
Peter Ajtai

0

Я думаю, что android: gravity = "center" должен работать


6
У меня не работает. Он центрирует текст, но drawableLeft остается слева.
Peter Ajtai

Вы должны объявить значок и текст под одним родителем, используйте android: gravity = "center" для родителя
devanshu_kaushik

0

Как предположил Роджа, до 4.0 не было прямого способа центрировать текст с возможностью рисования. И действительно, установка значения padding_left действительно перемещает объект рисования от границы. Поэтому я предлагаю, чтобы во время выполнения вы точно вычислили, сколько пикселей от левой границы должно быть у вашего объекта для рисования, а затем передайте его с помощью setPadding. Ваш расчет может быть примерно таким

int paddingLeft = (button.getWidth() - drawableWidth - textWidth) / 2;

Ширина вашего рисунка фиксирована, и вы можете посмотреть его, а также вычислить или угадать ширину текста.

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



0

открытый класс DrawableCenterTextView расширяет TextView {

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

public DrawableCenterTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public DrawableCenterTextView(Context context) {
    super(context);
}

@Override
protected void onDraw(Canvas canvas) {
    Drawable[] drawables = getCompoundDrawables();
    if (drawables != null) {
        Drawable drawableLeft = drawables[0];
        Drawable drawableRight = drawables[2];
        if (drawableLeft != null || drawableRight != null) {
            float textWidth = getPaint().measureText(getText().toString());
            int drawablePadding = getCompoundDrawablePadding();
            int drawableWidth = 0;
            if (drawableLeft != null)
                drawableWidth = drawableLeft.getIntrinsicWidth();
            else if (drawableRight != null) {
                drawableWidth = drawableRight.getIntrinsicWidth();
            }
            float bodyWidth = textWidth + drawableWidth + drawablePadding;
            canvas.translate((getWidth() - bodyWidth) / 2, 0);
        }
    }
    super.onDraw(canvas);
}

}


У меня это совсем не сработало. Не могли бы вы показать пример? Может, я не правильно использую
разработчик Android

0

Грязное исправление.

android:paddingTop="10dp"
android:drawableTop="@drawable/ic_src"

Правильное заполнение решает задачу. Однако для различного экрана используйте другое заполнение и поместите его в размерный ресурс в соответствующую папку значений.


0

Используйте RelativeLayout (контейнер) и android: layout_centerHorizontal = "true" , мой образец:

                <RelativeLayout
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1" >

                    <CheckBox
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_centerHorizontal="true"
                        android:layout_gravity="center"
                        android:layout_marginBottom="5dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginTop="5dp"
                        android:button="@drawable/bg_fav_detail"
                        android:drawablePadding="5dp"
                        android:text=" Favorite" />
                </RelativeLayout>

0

Другая возможность сохранить тему Button.

<Button
            android:id="@+id/pf_bt_edit"
            android:layout_height="@dimen/standard_height"
            android:layout_width="match_parent"
            />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_alignBottom="@id/pf_bt_edit"
            android:layout_alignLeft="@id/pf_bt_edit"
            android:layout_alignRight="@id/pf_bt_edit"
            android:layout_alignTop="@id/pf_bt_edit"
            android:layout_margin="@dimen/margin_10"
            android:clickable="false"
            android:elevation="20dp"
            android:gravity="center"
            android:orientation="horizontal"
            >

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:adjustViewBounds="true"
                android:clickable="false"
                android:src="@drawable/ic_edit_white_48dp"/>

            <TextView
                android:id="@+id/pf_tv_edit"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="@dimen/margin_5"
                android:clickable="false"
                android:gravity="center"
                android:text="@string/pf_bt_edit"/>

        </LinearLayout>

С помощью этого решения, если вы добавите @ color / your_color @ color / your_highlight_color в свою тему активности, у вас может быть тема Matherial на Lollipop с тенью и рябью, а для предыдущей версии - плоская кнопка с вашим цветом и цветом при нажатии.

Более того, с помощью этого решения автоизменение размера изображения

Результат: первый на устройстве Lollipop Второй: на устройстве pre lollipop 3-й: кнопка нажатия устройства Pre Lollipop

введите описание изображения здесь


0

Я центрировал textViewс помощью значка paddingLeftи выравнивал textView по левому краю | centerVertical . и для небольшого разрыва между представлением и значком я использовалdrawablePadding

         <Button
            android:id="@+id/have_it_main"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/textbox"
            android:drawableLeft="@drawable/have_it"
            android:drawablePadding="30dp"
            android:gravity="left|center_vertical"
            android:paddingLeft="60dp"
            android:text="Owner Contact"
            android:textColor="@android:color/white" />

2
Это не будет работать на многих экранах, только на том, на котором android:paddingLeftработало.
soshial

0

Это может быть старый / закрытый поток, но я поискал везде, не нашел ничего полезного, пока не решил создать свое собственное решение. Если кто-нибудь здесь пытается найти ответ, попробуйте этот, это может сэкономить вам минуту размышлений

          <LinearLayout
            android:id="@+id/llContainer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/selector"
            android:clickable="true"
            android:gravity="center"
            android:orientation="vertical"
            android:padding="10dp"
            android:textStyle="bold">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="This is a text" />

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/icon_image />


        </LinearLayout>

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

Обратите внимание, НЕ забудьте добавить android: clickable = "true" в основной контейнер (относительный или линейный) для выполнения действия.

Опять же, это может быть старая ветка, но все же может кому-то помочь.

-привет, надеюсь, что это поможет- счастливые коды.


0

Если вы используете одно из решений настраиваемого представления , будьте осторожны, потому что они часто не работают с длинным или многострочным текстом . Я переписал некоторые ответы, заменил onDraw()и понял, что это не так.


0

Я видел решения для выравнивания вытягиваемого в начале / влево, но ничего для вытягиваемого конца / вправо, поэтому я придумал это решение. Он использует динамически вычисляемые отступы для выравнивания текста и текста как с левой, так и с правой стороны.

class IconButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = R.attr.buttonStyle
) : AppCompatButton(context, attrs, defStyle) {

    init {
        maxLines = 1
    }

    override fun onDraw(canvas: Canvas) {
        val buttonContentWidth = (width - paddingLeft - paddingRight).toFloat()

        val textWidth = paint.measureText(text.toString())

        val drawable = compoundDrawables[0] ?: compoundDrawables[2]
        val drawableWidth = drawable?.intrinsicWidth ?: 0
        val drawablePadding = if (textWidth > 0 && drawable != null) compoundDrawablePadding else 0
        val bodyWidth = textWidth + drawableWidth.toFloat() + drawablePadding.toFloat()

        canvas.save()

        val padding = (buttonContentWidth - bodyWidth).toInt() / 2
        val leftOrRight = if (compoundDrawables[0] != null) 1 else -1
        setPadding(leftOrRight * padding, 0, -leftOrRight * padding, 0)

        super.onDraw(canvas)
        canvas.restore()
    }
}

Важно установить гравитацию в макете на «center_vertical | start» или «center_vertical | end» в зависимости от того, где вы устанавливаете значок. Например:

<com.stackoverflow.util.IconButton
        android:id="@+id/cancel_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:drawableStart="@drawable/cancel"
        android:drawablePadding="@dimen/padding_small"
        android:gravity="center_vertical|start"
        android:text="Cancel" />

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


-5

использовать это android:background="@drawable/ic_play_arrow_black_24dp"

просто установите фон для значка, который вы хотите центрировать

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.