Cómo centrar el icono y el texto en un botón de Android con el ancho establecido en "llenar principal"


118

Quiero tener un botón de Android con ícono + texto centrado en su interior. Estoy usando el atributo drawableLeft para configurar la imagen, esto funciona bien si el botón tiene un ancho de "wrap_content"pero necesito estirarlo al ancho máximo, así que uso el ancho "fill_parent". Esto mueve mi icono directamente a la izquierda del botón y quiero que tanto el icono como el texto estén centrados dentro del botón.

Intenté configurar el relleno, pero esto solo permite dar un valor fijo, por lo que no es lo que necesito. Necesito tener icono + texto alineado en el centro.

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

¿Alguna sugerencia sobre cómo podría lograrlo?


¿Es posible que no haya una solución fácil para esto? ¿Tengo que probar con un botón de parche 9 img con el ícono allí?
jloriente

Esta podría ser una solución. ¿El texto del botón será localizado o estático?
Octavian A. Damiean

Está localizado. ¿No hay otra solución para esto? Me las arreglé para hacerlo con un parche 9 pero tuve problemas al cambiar de lugar.
jloriente

¿Qué hay de usar un botón con TOP dibujable y agregarle algo de relleno?
Francesco

mal diseño del marco
Muhammad Babar

Respuestas:


75

android: drawableLeft siempre mantiene android: paddingLeft como una distancia desde el borde izquierdo. Cuando el botón no está configurado para android: width = "wrap_content", ¡siempre se colgará a la izquierda!

Con Android 4.0 (nivel de API 14) puede usar el atributo android: drawableStart para colocar un elemento de dibujo al comienzo del texto. La única solución compatible con versiones anteriores que se me ocurrió es usar un ImageSpan para crear un Texto + Imagen Spannable:

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

En mi caso, también necesitaba ajustar el atributo android: gravity del Botón para que pareciera centrado:

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

Agradable. La última línea debería serbutton.setText(buttonLabel)
AlexD

1
Unicode tiene un extenso conjunto de iconos de caracteres que son compatibles con cadenas en Android. Si puede encontrar uno aceptable, esta es una solución simple y tiene la ventaja adicional de que se escalará con el tamaño del texto. Por ejemplo, tiene un sobre para un icono de correo electrónico y un par de teléfonos diferentes para un botón de llamada.
GLee

1
Estoy confundido de cómo funcionó esto para cualquiera, para mí dibuja 2 íconos ... uno hacia la izquierda y otro directamente en el centro que se muestra en la parte superior del texto.
Justin

11
drawableStart no funcionará. Vea este hilo: stackoverflow.com/questions/15350990/… Además, parece que cuando configura el texto usando un spannable, el estilo se ignora.
Dapp

11
drawableStart no funciona y se agregó en el nivel de API 17 para admitir rtl
Silvia H

35

Sé que llegué tarde a responder esta pregunta, pero esto me ayudó:

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

Encontré esta solución desde aquí: la interfaz de usuario de Android tiene problemas: hacer un botón con texto e ícono centrados

ingrese la descripción de la imagen aquí


6
El problema con esto es que el botón no tiene el ancho del diseño del marco.
Clive Jefferies

29

Solía LinearLayout en lugar de botón . El OnClickListener , que necesito usar, funciona bien también para 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>

29

Todas las respuestas anteriores parecen estar desactualizadas

Puede usar el MaterialButtonahora que permite configurar la gravedad del icono.

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

ingrese la descripción de la imagen aquí

Para usar los componentes del material, obviamente necesitará:

Agregar una dependencia implementation 'com.google.android.material:material:1.3.0-alpha01'(usar la última versión)

Haga que su tema amplíe el tema Componentes de material

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

En caso de que no pueda hacerlo, extiéndalo desde el tema Material Bridge

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

¡Gracias! ¡Salvaste mi día! Funciona bien
Black_Zerg

9

Lo ajusto agregando relleno a izquierda y derecha de la siguiente manera:

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

El paddingLeft y paddingRight fue lo que me ayudó con mi centrado. votación para una solución fácil.
Arrie

2
¿Cómo gestiona el hecho de que su ancho es dinámico? Si gira la pantalla, todos sus iconos no estarán centrados, ¿verdad? Estoy enfrentando este problema en realidad
Jacks

¡Esta es la mejor respuesta!
Dody Rachmat Wicaksono

8

Recientemente me encontré con el mismo problema. Intenté encontrar una solución más barata, así que se me ocurrió esto.

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

A continuación, sólo llamar a la OnClickListenersobre LinearLayout.

Espero que esto ayude a alguien, ya que parece un problema muy común. :)


1
Esta es una buena idea, pero una mala solución. Puede lograr lo mismo con solo un TextView utilizando el atributo drawableLeft. Esto le permite ver un elemento de dibujo a la izquierda del texto.
muetzenflo

@muetzenflo sí, eso es correcto. pero cuando haga que textView coincida con el ancho principal, su elemento de diseño se moverá al extremo izquierdo incluso si centra su texto. por favor avíseme si me equivoco. y la pregunta es solo sobre eso.
Ankit Popli

ah lo siento .. Vine aquí exactamente por este problema y perdí el enfoque después de probar demasiadas cosas :) Supongo que no vi el bosque por los árboles. ¡Mi culpa!
muetzenflo

7

Puede utilizar un botón personalizado que se mida y se dibuje a sí mismo para acomodar un dibujable izquierdo. Encuentre el ejemplo y el uso aquí

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

Uso

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

Puede incluir código en su respuesta, que debería ser la forma preferida (si no es demasiado larga), ya que los enlaces pueden morir con el tiempo
Lukas Knuth

2
No es muy preciso, pero lo entiendo
Alex Semeniuk

Desplaza un texto a la derecha, pero no lo suficiente (una imagen se superpone al texto). Además, como otras soluciones de vista personalizada, no acepta texto largo correctamente.
CoolMind

5

Esta es mi solución que escribí hace 3 años. El botón tiene texto e ícono a la izquierda y está en el marco que es el botón real aquí y se puede estirar con fill_parent. No puedo probarlo de nuevo, pero estaba funcionando en ese entonces. Probablemente Button no tenga que usarse y pueda ser reemplazado por TextView, pero no lo probaré ahora y no cambia demasiado la funcionalidad aquí.

<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
Ahora veo que no estaba solo con esta solución :)
Renetik

4

Sé que esta pregunta es un poco más antigua, pero tal vez todavía esté abierto a sugerencias o soluciones:

Cree un "wrap_content" de RelativeLayout con la imagen del botón como fondo o el propio botón como primer elemento del diseño. Obtenga un LinearLayout y configúrelo en "layout_centerInParent" y "wrap_content". Luego configura tu Drawable como Imageview. Por último, configure un TextView con su texto (configuración regional).

entonces básicamente tienes esta estructura:

RelativeLayout
  Button
    LinearLayout
      ImageView
      TextView

o así:

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

Sé que con esta solución hay muchos elementos con los que lidiar, pero puedes crear muy fácilmente tu propio botón personalizado con él y también establecer la posición exacta del texto y los elementos de diseño :)


Este enfoque puede funcionar bien. En mi caso, todo lo que necesitaba era un RelativeLayout que contenía un TextView. El RelativeLayout obtuvo el fondo, el TextView obtiene el icono drawableLeft. Luego, en el código: adjunte onClickListener al RelativeLayout y findViewById para TextView por separado si es necesario
Stan Kurdziel

La primera estructura sugerida da la excepción "El botón no se puede convertir en ViewGroup".
Youngjae

4

Mi forma de resolverlo implicó rodear el botón con <View ../>elementos livianos que cambian de tamaño dinámicamente. A continuación se muestran varios ejemplos de lo que se puede lograr con esto:

Demo de Dev-iL

Tenga en cuenta que el área en la que se puede hacer clic de los botones en el ejemplo 3 es la misma que en 2 (es decir, con espacios), que es diferente del ejemplo 4, donde no hay espacios en los que "no se pueda hacer clic" en el medio.

Código:

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

Puede crear un widget personalizado:

La clase de 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);
}

}

El diseño 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>

Para utilizar este widget personalizado:

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

Debe proporcionar el espacio de nombres para los atributos personalizados xmlns: ibutton = "http://schemas.android.com/apk/res/com.test.android.xxx" donde com.test.android.xxx es el paquete raíz de la aplicación.

Simplemente colóquelo debajo de xmlns: android = "http://schemas.android.com/apk/res/android".

Lo último que necesitará son los atributos personalizados en attrs.xml.

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

Para un mejor posicionamiento, envuelva el botón personalizado dentro de un LinearLayout, si desea evitar problemas potenciales con los posicionamientos de RelativeLayout.

¡Disfrutar!


2

Tuve un problema similar, pero quería tener un diseño central sin texto y sin diseños ajustados. La solución fue crear un botón personalizado y agregar un elemento de dibujo más además de IZQUIERDA, DERECHA, SUPERIOR, INFERIOR. Uno puede modificar fácilmente la ubicación del dibujo y tenerlo en la posición deseada en relación con el texto.

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>

uso

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

¡Gracias! Eso es lo que estaba buscando.
MistaGreen

¿Podría ayudarme con esta pregunta, stackoverflow.com/questions/35912539/… , con su respuesta estoy muy cerca de eso, pero aparecen dos elementos de
diseño?

Esta solución coloca el elemento dibujable en el centro de un botón, un poco sobre el texto centrado.
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>

Coloque FrameLayout en LinearLayout y establezca la orientación en Horizontal.


1

Podrías poner el botón sobre un 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

¿Qué sucede si prueba android: gravity = "center_horizontal"?


5
No funciona. El texto está algo centrado pero el elemento drawableLeft se queda en el lado izquierdo.
Peter Ajtai


0

Como sugirió Rodja, antes de 4.0 no hay una forma directa de centrar el texto con el dibujable. Y, de hecho, establecer un valor padding_left aleja el elemento de diseño del borde. Por lo tanto, mi sugerencia es que en tiempo de ejecución calcule exactamente cuántos píxeles del borde izquierdo debe tener su dibujable y luego lo pase usando setPadding Su cálculo puede ser algo así como

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

El ancho de tus dibujables es fijo y puedes buscarlo y también puedes calcular o adivinar el ancho del texto.

Finalmente, necesitaría multiplicar el valor de relleno por la densidad de la pantalla, lo que puede hacer usando DisplayMetrics



0

La clase pública DrawableCenterTextView extiende 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);
}

}


Esto no funcionó para mí en absoluto. ¿Puede mostrar un ejemplo? Tal vez no lo use correctamente
desarrollador de Android

0

Arreglo sucio.

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

Calcular el acolchado correcto resuelve el propósito. Sin embargo, para una pantalla variada, use un relleno diferente y colóquelo en el recurso dimens en la carpeta de valor respectiva.


0

Use RelativeLayout (contenedor) y android: layout_centerHorizontal = "true" , mi muestra:

                <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

Otra posibilidad para mantener el tema del botón.

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

Con esta solución, si agrega @ color / your_color @ color / your_highlight_color en el tema de su actividad, puede tener el tema Matherial en Lollipop con sombra y ondulación, y para la versión anterior, el botón plano con su color y resaltar coor cuando lo presiona.

Además, con esta solución, el tamaño automático de la imagen

Resultado: Primero en el dispositivo Lollipop Segundo: En el dispositivo anterior a la piruleta 3 °: Presione el botón del dispositivo previo a la piruleta

ingrese la descripción de la imagen aquí


0

Me he centrado textViewcon el icono usando paddingLefty alineando textView a la izquierda | centerVertical . y para un pequeño espacio entre la vista y el ícono usé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
Esto no funcionará en muchas pantallas, solo en una para la que android:paddingLeftfuncionó.
soshial

0

Este puede ser un hilo antiguo / cerrado, pero he buscado en todas partes y no encontré nada útil, hasta que decidí crear mi propia solución. Si hay alguien aquí tratando de buscar una respuesta, pruebe esta, podría ahorrarle un minuto de pensamiento.

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

Debido a que el diseño lineal actúa como contenedor y el que tiene el selector, cuando hace clic en el diseño lineal completo, se verá exactamente como debería ser. si desea que ambos estén centrados, use relativo en lugar. Si lo desea centrado horizontalmente, cambie la orientación a horizontal.

Toma nota NO olvides agregar android: clickable = "true" a su contenedor principal (relativo o lineal) para que la acción tenga lugar.

Nuevamente, esto puede ser un hilo antiguo, pero aún puede ayudar a alguien allí.

-Saludos espero que ayude- happycodings.


0

Si utiliza una de las soluciones de vista personalizada , tenga cuidado, porque a menudo fallan en texto largo o de varias líneas . Reescribí algunas respuestas, las reemplacé onDraw()y entendí que era una forma incorrecta.


0

He visto soluciones para alinear elementos dibujables al inicio / izquierda, pero nada para el extremo dibujable / derecha, así que se me ocurrió esta solución. Utiliza rellenos calculados dinámicamente para alinear el texto y los elementos de diseño tanto en el lado izquierdo como en el derecho.

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

Es importante configurar la gravedad en su diseño en "center_vertical | start" o "center_vertical | end" dependiendo de dónde coloque el icono. Por ejemplo:

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

El único problema con esta implementación es que el botón solo puede tener una sola línea de texto; de lo contrario, el área del texto llena el botón y los rellenos serán 0.


-5

utilizar este android:background="@drawable/ic_play_arrow_black_24dp"

simplemente establezca el fondo en el icono que desea centrar

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.