2012-04-01 9 views
6

me quedé atrapado en un problema extraño con Android - Quiero tener un botón que se parece a esto:Android: cómo crear un botón con la imagen y el texto que son a la vez centrado

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

y el grupo ([icono] < 5px> [texto de texto]) debe estar centrado. Tenga en cuenta que 5px se usa solo como un marcador de posición para cualquier relleno que desee tener entre el icono y el texto

Encontré algunas respuestas aquí que fueron más o menos gravitantes sobre la configuración de un fondo (que no quiero hacer porque tengo otro fondo) o usar la propiedad android: drawableLeft para establecer el icono.

Sin embargo, parece que la documentación del método setCompoundDrawablesWithIntrinsicBounds es un poco engañosa (see here). Indica que la imagen se coloca en el lado izquierdo/derecho/superior/inferior del TEXTO que no es verdadero. El icono se coloca en el lado correspondiente del BOTÓN. Por ejemplo:

Ajuste del androide: drawableLeft propiedad pone el icono en la posición más a la izquierda y me pone esto (con el centro de gravedad):

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

o esto (con la gravedad IZQUIERDA):

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

Ambos son feos como demonios :(

he encontrado una solución que tiene este aspecto:

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

Y funciona más o menos, pero no encuentro a mi gusto por las razones siguientes:

  • se requiere conocer el ancho botón. Con los botones de tamaño automático, no se conocerá hasta que se realice el diseño real. Google recomienda usar un oyente para conocer el ancho real después de que se realiza el renderizado, pero esto complica enormemente el código.
  • Siento que estoy tomando la responsabilidad de diseño del motor de diseño Android

¿No hay una solución más elegante?

+0

esperanza para que usted había resuelto el problema – Ishu

Respuesta

10

Puede usar la siguiente subclase Button para lograr este efecto.

  1. Pegue esta clase en su proyecto y modifique el nombre del paquete si lo desea.
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. Modificar la disposición de utilizar esta nueva subclase en lugar de llanura 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. Si desea agregar relleno entre el dibujable y el texto, añada lo siguiente a onCreate de su actividad:

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

Esta subclase también es compatible con drawableRight. No es compatible con más de un dibujable.

Si desea más características, tales como la posibilidad de especificar el iconPadding directamente en su diseño XML, que tienen una forma simple library that supports this.

-3

yo probamos este eclipse y en surtidor sin errores:

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

Por lo tanto, supongo que se podría añadir una vista de imagen y texto en una disposición, en sí dentro de un botón, y el centro de la disposición.

Saludos cordiales.

+0

Sólo debe ser horizontal – Gangnus

+0

yo diría nya nya nya, si no estaban perfectamente bien. – pouzzler

+0

Y lo tienes vertical :-) – Gangnus

0

También puede considerar el uso de una vista personalizada para crear un botón personalizado.

Esto podría ser fácil o extremadamente complejo.

Sería fácil si todo lo que necesita hacer es anular onDraw(). Será más complejo si necesita diseñar múltiples vistas.

+0

Aceptaré esta respuesta porque es correcta y proporciona una solución, aunque no estoy seguro de poder clasificarla como una solución "más elegante". Mi punto es que realmente es un sentido común esperar que el texto y el ícono estén centrados cuando llamas a setGravity (CENTER) y crear componentes personalizados solo por ESO es un poco exagerado. – vap78

0

es escribir Button en LinearLayout. Algo como esto

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