Android - Espaciado entre CheckBox y texto

256

¿Hay una manera fácil de agregar relleno entre la casilla de verificación en un control CheckBox y el texto asociado?

No puedo simplemente agregar espacios iniciales, porque mi etiqueta es de varias líneas.

Tal como está, el texto está demasiado cerca de la casilla de verificación: texto alternativo

DougW
fuente
1
Una solución simple sería usar un TextViewcon drawableLefty usar drawablePaddingpara dar espacio al texto. En el código solo alterna los estados seleccionados y no seleccionados.
Muhammad Babar
Acabo de notar un nuevo atributo xml llamado android: drawablePadding, que se supone que establece el espacio entre el dibujo y el texto. No lo intenté, pero creo que es la solución "posterior a los hechos" de Google para este problema.
Peri Hartman

Respuestas:

333

Odio responder mi propia pregunta, pero en este caso creo que necesito hacerlo. Después de verificarlo, @Falmarri estaba en el camino correcto con su respuesta. El problema es que el control CheckBox de Android ya usa la propiedad android: paddingLeft para obtener el texto donde está.

La línea roja muestra el valor de desplazamiento paddingLeft de todo el CheckBox

texto alternativo

Si acabo de anular ese relleno en mi diseño XML, arruina el diseño. Esto es lo que hace la configuración paddingLeft = "0":

texto alternativo

Resulta que no puedes arreglar esto en XML. Lo tienes que hacer en código. Aquí está mi fragmento con un aumento de relleno codificado de 10dp.

final float scale = this.getResources().getDisplayMetrics().density;
checkBox.setPadding(checkBox.getPaddingLeft() + (int)(10.0f * scale + 0.5f),
        checkBox.getPaddingTop(),
        checkBox.getPaddingRight(),
        checkBox.getPaddingBottom());

Esto le da lo siguiente, donde la línea verde es el aumento en el relleno. Esto es más seguro que codificar un valor, ya que diferentes dispositivos podrían usar diferentes elementos dibujables para la casilla de verificación.

texto alternativo

ACTUALIZACIÓN: como la gente ha mencionado recientemente en las respuestas a continuación, este comportamiento aparentemente ha cambiado en Jelly Bean (4.2). Su aplicación deberá verificar en qué versión se está ejecutando y utilizar el método apropiado.

Para 4.3+ es simplemente establecer padding_left. Ver la respuesta de htafoya para más detalles.

DougW
fuente
108
No tiene nada de malo responder a su propia pregunta: es probable que otra persona tenga este problema en el futuro y usted haya dado una respuesta buena e integral.
AndrewKS
44
¿Qué hay de malo con solo configurar paddingLeft="48sp"? Funciona bien aquí, incluso si cambio la escala y la orientación. Su código me dio valores de relleno erráticos sobre una lista de elementos.
harpo
55
@harpo: no tiene garantías de que diferentes fabricantes de dispositivos no utilicen gráficos diferentes para la casilla de verificación, lo que significa que su relleno codificado puede romper su diseño visual en diferentes dispositivos. Como estoy leyendo el relleno actual y agregando eso, no será un problema, pero debes asegurarte de hacerlo solo una vez.
DougW
2
@Blundell: no necesariamente. El código abierto de Android. Un proveedor de dispositivos podría sustituir un gráfico totalmente diferente con un tamaño totalmente diferente. Les encanta hacer cosas así por alguna razón.
DougW
2
Desafortunadamente, no puede usar esta solución en getView()un Adaptador personalizado (si recicla sus vistas), ya que el relleno aumentará infinitamente. Para solucionar este problema, tuve que usar algo como esto: boolean isHackNeeded = Build.VERSION.SDK_INT < 17; float scale = context.getResources().getDisplayMetrics().density; if (isHackNeeded) {CheckBox rb = new CheckBox(context); this.PADDING = rb.getPaddingLeft() + Math.round(10.0f * scale); } else { this.PADDING = Math.round(10.0f * scale); }. Y luego uso PADDINGpara cada CheckBox que check.setPadding(PADDING, check.getPaddingTop() ...
inflo
133

Dada la respuesta de @DougW, lo que hago para administrar la versión es más simple, agrego a mi vista de casilla de verificación:

android:paddingLeft="@dimen/padding_checkbox"

donde el dimen se encuentra en dos carpetas de valores:

valores

<resources>

    <dimen name="padding_checkbox">0dp</dimen>

</resources>

valores-v17 (4.2 JellyBean)

<resources>

    <dimen name="padding_checkbox">10dp</dimen>

</resources>

Tengo un cheque personalizado, use el dps para su mejor opción.

htafoya
fuente
2
Esta es la mejor respuesta hasta ahora. aunque, realmente debería ser values-v17como se introdujo la solución en API 17 (según algunas publicaciones anteriores)
icecreamman
Una respuesta perfecta, solo para apis anteriores (valores / dimens) configuré padding_checkbox en 0dip (en el margen API 10 ya es enorme) y para values-v17 10dip como sugirió htafoya.
Yar
70

Use el atributo en android:drawableLeftlugar de android:button. Para establecer el relleno entre el dibujo y el uso del texto android:drawablePadding. Para posicionar el uso dibujable android:paddingLeft.

<CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:button="@null"
        android:drawableLeft="@drawable/check_selector"
        android:drawablePadding="-50dp"
        android:paddingLeft="40dp"
        />

resultado

Trokhymets romanos
fuente
1
Hola, este es un buen método, pero ten en cuenta que obtienes un margen izquierdo adicional debido a la imagen predeterminada de la casilla de verificación ... cualquier solución para eso
Code_Life
44
conjunto android:background="@android:color/transparent"y el margen izquierdo desaparecerán
madeuz
2
El código anterior funcionó perfectamente para mis botones de radio, y es consistente a través del límite del sistema operativo 4.2. ¡Gracias!
gnichola
1
Esto debería clasificarse mucho más alto. Como dijo @gnichola, esto funciona en todas las versiones de Android y es una solución bastante limpia. Cree un estilo y asígnelo en su tema de esta manera: de <item name="android:checkboxStyle">@style/CheckBox</item> esa manera, tiene el estilo definido una vez y referenciado solo una vez.
Rosomack
1
También establezca el fondo en nulo (o algo personalizado), de lo contrario, lollipop + obtiene un efecto de ondulación circular masivo que abarca toda la vista. Puede usar un botón v21 que se pueda dibujar utilizando las etiquetas <ripple> para volver a colocar una onda más apropiada.
Tom
34

Android 4.2 Jelly Bean (API 17) pone el relleno de texto a la izquierda del botón Dibujable (lado derecho de las entradas). También funciona para el modo RTL.

Antes de 4.2 paddingLeft ignoraba el buttonDrawable: se tomó del borde izquierdo de la vista CompoundButton.

Puede resolverlo a través de XML: establezca paddingLeft en buttonDrawable.width + requiredSpace en los androides más antiguos. Configúrelo en requiredSpace solo en API 17 en adelante. Por ejemplo, use los recursos de dimensión y anule en la carpeta de recursos values-v17.

El cambio se introdujo a través de android.widget.CompoundButton.getCompoundPaddingLeft ();

kotucz
fuente
44
Es la única respuesta correcta aquí: señala el problema y proporciona soluciones simples, que he utilizado con éxito en múltiples aplicaciones comerciales.
madej
1
¿Cómo se obtiene buttonDrawable.width en XML o se codifica?
Jared Kells
1
Me las arreglé para solucionar este problema en un código antiguo eliminando android:background="@android:color/transparent".
Sebek
La respuesta aceptada es agradable y funciona, pero esta es simple y efectiva. Esta debe ser la respuesta aceptada.
Reaz murmuró el
27

Sí, puede agregar relleno agregando relleno.

android:padding=5dp

Falmarri
fuente
44
Esto realmente funciona ... más o menos. Por un lado, solo se necesita paddingLeft, no todo el relleno. Sin embargo, parece que paddingLeft ya está configurado en un valor de alrededor de 40dp. Si lo configuro> 40dp se aleja, si lo configuro <40dp se mueve debajo de la casilla de verificación. Voy a marcar esto como correcto y abriré otra pregunta, porque tengo dudas sobre eso.
DougW
Bueno, no tengo idea sin ver tu diseño.
Falmarri
sí, no funciona ... en particular dispositivo Samsung Tengo un problema.
Ranjith Kumar
1
¡Agregar relleno al agregar relleno suena legítimo!
Sermilion
21

Si desea un diseño limpio sin códigos, use:

<CheckBox
   android:id="@+id/checkBox1"
   android:layout_height="wrap_content"
   android:layout_width="wrap_content"
   android:drawableLeft="@android:color/transparent"
   android:drawablePadding="10dp"
   android:text="CheckBox"/>

El truco consiste en establecer el color en transparente para android:drawableLefty asignar un valor para android:drawablePadding. Además, la transparencia le permite utilizar esta técnica en cualquier color de fondo sin el efecto secundario, como la falta de coincidencia de color.

ChuongPham
fuente
16

API 17 y superior, puede usar:

android: paddingStart = "24dp"

API 16 y a continuación, puede usar:

android: paddingLeft = "24dp"

Inmer
fuente
1
Muy buena respuesta. No puedo imaginar cómo el relleno dará el espacio entre la casilla de verificación y el texto. Por lo general, Relleno a la izquierda significa a la izquierda del componente.
Mohamed Ibrahim
14

En mi caso, resolví este problema usando el siguiente atributo CheckBox en el XML:

* *

android: paddingLeft = "@ dimen / activity_horizontal_margin"

* *

Mohammad Zakaria
fuente
Muy buena respuesta. No puedo imaginar cómo el relleno dará el espacio entre la casilla de verificación y el texto. Por lo general, Relleno a la izquierda significa la izquierda del componente.
Mohamed Ibrahim
13

Solución simple, agregue esta línea en las propiedades de CheckBox , reemplace 10dp con el valor de espacio deseado

android:paddingLeft="10dp"
Naveed Ahmad
fuente
10

No conozco chicos, pero probé

<CheckBox android:paddingLeft="8mm" y solo mueve el texto hacia la derecha, no todo el control.

Me queda bien.

Tiago
fuente
1
No lo he probado recientemente, por lo que es posible que funcione en un dispositivo específico o en una versión más reciente del sistema operativo Android. Sin embargo, recomiendo encarecidamente que pruebe en diferentes configuraciones, porque definitivamente esto no funcionó en el momento en que hice esta pregunta.
DougW
Veo que esto se comporta de manera diferente entre 2.3.3 y 4.2 (no estoy seguro de dónde ocurrió el cambio).
Nate
¿Quieres decir dp no mm?
Chrispix
10

¿Por qué no simplemente extender el CheckBox de Android para tener un mejor relleno? De esa manera, en lugar de tener que arreglarlo en el código cada vez que use CheckBox, puede usar el CheckBox fijo.

Primero Extender CheckBox:

package com.whatever;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.CheckBox;

/**
 * This extends the Android CheckBox to add some more padding so the text is not on top of the
 * CheckBox.
 */
public class CheckBoxWithPaddingFix extends CheckBox {

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

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

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

    @Override
    public int getCompoundPaddingLeft() {
        final float scale = this.getResources().getDisplayMetrics().density;
        return (super.getCompoundPaddingLeft() + (int) (10.0f * scale + 0.5f));
    }
}

Segundo en su xml en lugar de crear un CheckBox normal, cree su extendido

<com.whatever.CheckBoxWithPaddingFix
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello there" />
w.donahue
fuente
2
Debería agregar un 'if' para evitar hacerlo si OS> 4.2 porque en Jelly Bean "arreglaron" esto.
Martin Marconcini
1
En realidad> = 4.2 (17).
Aleks N.
6

Acabo de concluir sobre esto:

Anule CheckBox y agregue este método si tiene un dibujo personalizado:

@Override
public int getCompoundPaddingLeft() {

    // Workarround for version codes < Jelly bean 4.2
    // The system does not apply the same padding. Explantion:
    // http://stackoverflow.com/questions/4037795/android-spacing-between-checkbox-and-text/4038195#4038195

    int compoundPaddingLeft = super.getCompoundPaddingLeft();

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        Drawable drawable = getResources().getDrawable( YOUR CUSTOM DRAWABLE );
        return compoundPaddingLeft + (drawable != null ? drawable.getIntrinsicWidth() : 0);
    } else {
        return compoundPaddingLeft;
    }

}

o esto si usa el sistema dibujable:

@Override
public int getCompoundPaddingLeft() {

    // Workarround for version codes < Jelly bean 4.2
    // The system does not apply the same padding. Explantion:
    // http://stackoverflow.com/questions/4037795/android-spacing-between-checkbox-and-text/4038195#4038195

    int compoundPaddingLeft = super.getCompoundPaddingLeft();

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        final float scale = this.getResources().getDisplayMetrics().density;
        return compoundPaddingLeft + (drawable != null ? (int)(10.0f * scale + 0.5f) : 0);
    } else {
        return compoundPaddingLeft;
    }

}

Gracias por la respuesta :)

PaNaVTEC
fuente
4

Este comportamiento parece haber cambiado en Jelly Bean. El truco paddingLeft agrega relleno adicional, haciendo que el texto se vea demasiado a la derecha. ¿Alguien más nota eso?

extremo
fuente
¡Gracias por la actualización! He agregado una nota a mi respuesta sobre esto.
DougW
4

Para espacio entre la marca de verificación y el uso del texto:

android:paddingLeft="10dp"

Pero se convierte en más de 10dp, porque la marca de verificación contiene relleno (alrededor de 5dp) alrededor. Si desea eliminar el relleno, consulte Cómo eliminar el relleno alrededor de Android CheckBox :

android:paddingLeft="-5dp"
android:layout_marginStart="-5dp"
android:layout_marginLeft="-5dp"
// or android:translationX="-5dp" instead of layout_marginLeft
CoolMind
fuente
2
<CheckBox
        android:paddingRight="12dip" />
AndrewKS
fuente
@AndrewKS - Probado. Como se esperaba, esto agrega relleno a todo el control, no entre la casilla de verificación y el texto.
DougW
Probablemente sea mejor tener el texto en un TextView separado.
AndrewKS
@AndrewKS - Mala idea de usabilidad. Quiero que el usuario pueda tocar el texto y seleccionar / deseleccionar la casilla de verificación. También rompe muchas funciones de accesibilidad, de la misma manera que si lo hicieras en una página web.
DougW
Bad idea for usabilityNo, no es. Coloque tanto la casilla de verificación como la vista de texto en un diseño lineal y haga que esa distribución lineal sea táctil.
Falmarri
1
-1 Esta respuesta no aborda el problema planteado en la pregunta, que trata sobre la brecha entre la imagen y el texto
David Laing
2

Si tiene un selector de imagen personalizado para la casilla de verificación o el botón de radio, debe establecer el mismo botón y propiedad de fondo como esta:

            <CheckBox
                android:id="@+id/filter_checkbox_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:button="@drawable/selector_checkbox_filter"
                android:background="@drawable/selector_checkbox_filter" />

Puede controlar el tamaño de la casilla de verificación o el relleno del botón de opción con la propiedad de fondo.

Ilya Lisway
fuente
No, no tienes que hacer esto. Esto no es aceptable si tiene un fondo personalizado que es diferente de la casilla de verificación / glifo de botón de radio.
andr
2

solo necesitas tener un parámetro en el archivo xml

android:paddingLeft="20dp"
tej shah
fuente
2

Establecer minHeight y minWidth en 0dpfue la solución más limpia y directa para mí en Android 9 API 28:

<CheckBox
        android:id="@+id/checkbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minHeight="0dp"
        android:minWidth="0dp" />
ManuelTS
fuente
1

Si está creando botones personalizados, por ejemplo, vea el aspecto de cambio del tutorial de la casilla de verificación

Luego, simplemente aumente el ancho de btn_check_label_background.9.png agregando una o dos columnas más de píxeles transparentes en el centro de la imagen; deje los marcadores de 9 parches como están.

Keith Beardmore
fuente
1

Lo que hice fue tener un TextViewy un CheckBoxdentro de un (Relativo) Layout. Las TextViewmuestra el texto que desea que el usuario vea, y el CheckBoxno tiene ningún texto. De esa manera, puedo establecer la posición / relleno de CheckBoxdonde quiera.

mbmc
fuente
1

Tuve el mismo problema con un Galaxy S3 mini (Android 4.1.2) y simplemente hice que mi casilla de verificación personalizada extendiera AppCompatCheckBox en lugar de CheckBox. Ahora funciona a la perfección.

Quentin G.
fuente
0

Debe obtener el tamaño de la imagen que está utilizando para agregar su relleno a este tamaño. En los componentes internos de Android, obtienen el dibujo que especifiques en src y luego usan su tamaño. Dado que es una variable privada y no hay captadores a los que no puede acceder. Tampoco puede obtener el com.android.internal.R.styleable.CompoundButton y obtener el dibujable desde allí.

Por lo tanto, debe crear su propio estilo (es decir, custom_src) o puede agregarlo directamente en su implementación del RadioButton:

public class CustomRadioButton extends RadioButton {

    private Drawable mButtonDrawable = null;

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

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

    public CustomRadioButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mButtonDrawable = context.getResources().getDrawable(R.drawable.rbtn_green);
        setButtonDrawable(mButtonDrawable);
    }

    @Override
    public int getCompoundPaddingLeft() {
        if (Util.getAPILevel() <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            if (drawable != null) {
                paddingLeft += drawable.getIntrinsicWidth();
            }
        }
        return paddingLeft;
    }
}
hudomju
fuente
0

Como probablemente use un selector dibujable para su android:buttonpropiedad, debe agregar android:constantSize="true"y / o especificar un sorteo predeterminado como este:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true">
  <item android:drawable="@drawable/check_on" android:state_checked="true"/>
  <item android:drawable="@drawable/check_off"/>
</selector>

Después de eso, debe especificar el android:paddingLeftatributo en su casilla de verificación xml.

Contras:

En el editor de diseño, verá el texto debajo de la casilla de verificación con la API 16 y debajo, en ese caso puede solucionarlo creando su clase de casilla de verificación personalizada como se sugiere pero para la API de nivel 16.

Razón fundamental:

es un error ya que la StateListDrawable#getIntrinsicWidth()llamada se usa internamente CompoundButtonpero puede devolver < 0valor si no hay un estado actual y no se usa un tamaño constante.

Gianluca P.
fuente
0

Todo lo que tiene que hacer para superar este problema es agregar android:singleLine="true"al checkBoxdiseño xml de su Android:

<CheckBox 
   android:id="@+id/your_check_box"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:singleLine="true"
   android:background="@android:color/transparent"
   android:text="@string/your_string"/>

y nada especial se agregará mediante programación.

Muhammed Refaat
fuente
0

La imagen de la casilla de verificación se superpuso cuando utilicé mis propios dibujables del selector, lo resolví usando el siguiente código:

CheckBox cb = new CheckBox(mActivity);
cb.setText("Hi");
cb.setButtonDrawable(R.drawable.check_box_selector);
cb.setChecked(true);
cb.setPadding(cb.getPaddingLeft(), padding, padding, padding);

Gracias a Alex Semeniuk

Jaiprakash Soni
fuente
0

Termino con este problema cambiando las imágenes. Acabo de agregar un fondo transparente adicional en los archivos png. Esta solución funciona excelente en todas las API.

Leo Droidcoder
fuente
0

Tal vez sea demasiado tarde, pero he creado métodos de utilidad para gestionar este problema.

Simplemente agregue estos métodos a sus utilidades:

public static void setCheckBoxOffset(@NonNull  CheckBox checkBox, @DimenRes int offsetRes) {
    float offset = checkBox.getResources().getDimension(offsetRes);
    setCheckBoxOffsetPx(checkBox, offset);
}

public static void setCheckBoxOffsetPx(@NonNull CheckBox checkBox, float offsetInPx) {
    int leftPadding;
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
        leftPadding = checkBox.getPaddingLeft() + (int) (offsetInPx + 0.5f);
    } else {
        leftPadding = (int) (offsetInPx + 0.5f);
    }
    checkBox.setPadding(leftPadding,
            checkBox.getPaddingTop(),
            checkBox.getPaddingRight(),
            checkBox.getPaddingBottom());
}

Y use así:

    ViewUtils.setCheckBoxOffset(mAgreeTerms, R.dimen.space_medium);

o así:

    // Be careful with this usage, because it sets padding in pixels, not in dp!
    ViewUtils.setCheckBoxOffsetPx(mAgreeTerms, 100f);
Oleksandr
fuente
-1

En lugar de ajustar el texto para Checkbox, hice lo siguiente y funcionó para todos los dispositivos. 1) En XML, agregue la casilla de verificación y una vista de texto adyacente a una tras otra; manteniendo cierta distancia. 2) Establezca el tamaño del texto de la casilla de verificación en 0sp. 3) Agregue texto relativo a esa vista de texto al lado de la casilla de verificación.

Pankaj Deshpande
fuente
-3

<CheckBox android:drawablePadding="16dip" - El relleno entre los dibujables y el texto.

usuario1879118
fuente