Cómo centrar el icono y el texto en un botón de Android con el ancho configurado para “completar el elemento principal”

Quiero tener un botón de Android con ícono + texto centrado dentro de él. Estoy usando el atributo drawableLeft para establecer la imagen, esto funciona bien si el botón tiene un ancho de "wrap_content" pero necesito estirar al ancho máximo así que utilizo width "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 el icono + texto alineado en el centro.

 

¿Alguna sugerencia sobre cómo podría lograr eso?

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

Con Android 4.0 (API nivel 14) puede usar el atributo android: drawableStart para colocar un dibujante al comienzo del texto. La única solución compatible con versiones anteriores que he encontrado es el uso de ImageSpan para crear un texto + imagen que se puede abrir:

 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 necesité ajustar el atributo android: gravity del botón para que se vea centrado:

  

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

    

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

enter image description here

Usé LinearLayout en lugar de Button . El OnClickListener , que necesito usar también funciona bien para LinearLayout.

     

Puede usar un botón personalizado que mide y dibuja para acomodar un dibujo a la izquierda. Encuentre ejemplos y 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.restre(); 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.restre(); } @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

  

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

      

Luego simplemente llame a OnClickListener en LinearLayout .

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

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

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

así que 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 extraíbles 🙂

Mi manera de resolverlo consistía en rodear el botón con elementos livianos que tamaño dinámicamente. A continuación hay varios ejemplos de lo que se puede lograr con esto:

Demostración por Dev-iL

Tenga en cuenta que el área seleccionable 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 “no seleccionables” entre ellos.

Código:

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

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

  

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

     

Para usar este widget personalizado:

  

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 ubíquelo debajo de xmlns: android = “http://schemas.android.com/apk/res/android”.

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

En attrs.xml

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

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

¡Disfrutar!

Tenía un problema similar, pero quería tener un centro dibujable sin texto y sin diseños envueltos. La solución fue crear un botón personalizado y agregar uno más dibujable además de IZQUIERDA, DERECHA, ARRIBA, ABAJO. Uno puede modificar fácilmente la colocación dibujable y tenerla 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.restre(); } } } 

attrs.xml

       

uso

  
     

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

Puedes poner el botón sobre un LinearLayout

       

Esta es mi solución …

    

Intenta usar esta biblioteca

OmegaCenterIconButton

enter image description here

¿Qué sucede si pruebas con android: gravity = “center_horizontal”?

Creo que Android: gravedad = “centro” debería funcionar

Según lo sugerido por Rodja, antes de 4.0 no hay una manera directa de centrar el texto con el dibujable. Y, de hecho, establecer un valor padding_left aleja el dibujo del borde. Por lo tanto, mi sugerencia es que, en tiempo de ejecución, se calcula exactamente cuántos píxeles del borde izquierdo necesita para dibujar y luego se pasa usando setPadding. Su cálculo puede ser algo así como

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

El ancho de los dibujables es fijo y puede buscarlo y también puede 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

No lo pruebo pero parece que puedes usar la biblioteca CenteredContentButton

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

}

Arreglo sucio

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

Calcular el relleno correcto resuelve el propósito. Sin embargo, para una pantalla variada, use diferentes rellenos y coloque ese recurso en dimens en la carpeta de valores respectivos.

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

     

Otra posibilidad de mantener el tema de Button.

      

Con esta solución, si agregas @ color / your_color @ color / your_highlight_color en tu tema de actividad, puedes tener el tema Matherial en Lollipop con sombra y rizo, y para el botón plano de versión anterior con tu color y resaltar coor al presionarlo.

Por otra parte, con esta solución, cambiar el tamaño de la imagen

Resultado: Primero en el dispositivo Lollipop. Segundo: En el dispositivo pre lollipop. 3: Presione el botón Pre lollipop.

enter image description here

He centrado textView con el icono usando paddingLeft alineando textView a left | centerVertical . y para un pequeño espacio entre la vista y el ícono utilicé drawablePadding

   

Puede que se trate de un hilo antiguo / cerrado, pero he buscado en todas partes y no he encontrado algo útil, hasta que decidí crear mi propia solución. Si hay alguien aquí tratando de buscar una respuesta, pruebe esta, puede ahorrarle un minuto de reflexión

    
		      	

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

simplemente establece el fondo del ícono que quieres centrar

Si usa una de las soluciones de vista personalizada , tenga cuidado, ya que a menudo fallan en el texto largo o multilínea . Reescribí algunas respuestas, reemplacé onDraw() y entendí que esa era una manera incorrecta.