Android - Espaçamento entre CheckBox e texto

256

Existe uma maneira fácil de adicionar preenchimento entre a caixa de seleção em um controle CheckBox e o texto associado?

Não posso simplesmente adicionar espaços à esquerda, porque meu rótulo é multilinhas.

Como está, o texto está muito perto da caixa de seleção: texto alternativo

DougW
fonte
1
Uma solução simples seria usar TextViewwith drawableLefte use drawablePaddingpara dar espaço ao texto. No código, apenas alterne os estados selecionados e não selecionados.
Muhammad Babar
Acabei de notar um novo atributo xml chamado android: drawablePadding, que deve definir o espaçamento entre o drawable e o texto. Não tentei, mas acho que é a correção "posterior ao fato" do Google para esse problema.
Peri Hartman

Respostas:

333

Detesto responder à minha própria pergunta, mas neste caso acho que preciso. Depois de conferir, @Falmarri estava no caminho certo com sua resposta. O problema é que o controle CheckBox do Android já usa a propriedade android: paddingLeft para obter o texto onde está.

A linha vermelha mostra o valor de deslocamento paddingLeft de toda a CheckBox

texto alternativo

Se eu simplesmente substituir esse preenchimento no meu layout XML, ele estragará o layout. Aqui está o que a configuração paddingLeft = "0" faz:

texto alternativo

Acontece que você não pode corrigir isso em XML. Você faz isso no código. Aqui está o meu snippet com um aumento de 10dp no preenchimento codificado.

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

Isso fornece o seguinte, onde a linha verde é o aumento do preenchimento. Isso é mais seguro do que codificar um valor, uma vez que diferentes dispositivos podem usar diferentes drawables para a caixa de seleção.

texto alternativo

ATUALIZAÇÃO - Como as pessoas mencionaram recentemente nas respostas abaixo, esse comportamento aparentemente mudou em Jelly Bean (4.2). Seu aplicativo precisará verificar em qual versão está sendo executado e usar o método apropriado.

Para 4.3+, é simplesmente definir padding_left. Veja a resposta da htafoya para obter detalhes.

DougW
fonte
108
Não há nada errado em responder à sua própria pergunta - alguém provavelmente terá esse problema no futuro e você acabou de dar uma resposta boa e abrangente.
AndrewKS
4
O que há de errado em apenas definir paddingLeft="48sp"? Funciona bem aqui, mesmo que eu mude de escala e orientação. Seu código me forneceu valores irregulares de preenchimento em uma lista de itens.
harpo 28/03
5
@harpo - Você não tem garantias de que diferentes fabricantes de dispositivos não usem gráficos diferentes para a caixa de seleção, o que significa que seu preenchimento codificado pode danificar seu layout visual em diferentes dispositivos. Desde que eu estou lendo o preenchimento atual e adicionando a ele, isso não será um problema, mas você precisa se certificar de fazê-lo apenas uma vez.
DougW 29/03
2
@ Blundell - Não necessariamente. Código aberto do Android. Um fornecedor de dispositivos pode substituir um gráfico totalmente diferente por um tamanho totalmente diferente. Eles adoram fazer coisas assim por algum motivo.
DougW 20/05
2
Infelizmente, você não pode usar esta solução no getView()adaptador personalizado (se reciclar suas visualizações), pois o preenchimento aumentará infinitamente. Para corrigir esse problema que eu tinha que usar algo como isto: 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); }. E depois usar PADDINGpara cada CheckBox I inflar:check.setPadding(PADDING, check.getPaddingTop() ...
Alex Semeniuk
133

Dada a resposta @DougW, o que faço para gerenciar a versão é mais simples, adiciono à minha exibição da caixa de seleção:

android:paddingLeft="@dimen/padding_checkbox"

onde o dimen é encontrado em duas pastas de valores:

valores

<resources>

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

</resources>

valores-v17 (4.2 JellyBean)

<resources>

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

</resources>

Eu tenho uma verificação personalizada, use os dps para sua melhor escolha.

htafoya
fonte
2
Esta é a melhor resposta até agora. embora, ele realmente deve ser values-v17como a correção foi introduzida na API 17 (de acordo com alguns posts acima)
icecreamman
Uma resposta perfeita, apenas para APIs mais antigas (valores / dimens), defino padding_checkbox como 0dip (na margem API 10 já é grande) e para valores-v17 10dip, como sugerido pela htafoya.
30716 Yar
70

Use o atributo em android:drawableLeftvez de android:button. Para definir o preenchimento entre o drawable e o uso de texto android:drawablePadding. Para posicionar o uso desenhável 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
fonte
1
Oi, Isso é bom método, mas aviso que u obter margem extra esquerda bcoz da imagem padrão de caixa .. quaisquer soluções para isso
Code_Life
4
conjunto android:background="@android:color/transparent"e margem esquerda irá desaparecer
madeuz
2
O código acima funcionou perfeitamente para meus botões de opção e é consistente no limite do sistema operacional 4.2. Obrigado!
Gnichola #
1
Isso deve ser classificado muito mais alto. Como @gnichola disse, isso funciona nas versões do Android e é uma solução bastante limpa. Crie um estilo e atribua-o ao seu tema assim: <item name="android:checkboxStyle">@style/CheckBox</item> dessa forma, você tem o estilo definido uma vez e referenciado apenas uma vez.
Rosomack
1
Também defina o plano de fundo como nulo (ou algo personalizado), caso contrário, o lollipop + obtém um enorme efeito de ondulação do círculo que abrange toda a visualização. Você pode usar um botão de desenho v21 usando as tags <ripple> para colocar uma ondulação mais apropriada de volta.
Tom
34

O Android 4.2 Jelly Bean (API 17) coloca o texto paddingLeft a partir do botão Drawable (ints borda direita). Também funciona no modo RTL.

Antes de 4.2 paddingLeft estava ignorando o buttonDrawable - ele foi retirado da borda esquerda da visualização CompoundButton.

Você pode resolvê-lo via XML - defina paddingLeft como buttonDrawable.width + requiredSpace em androids mais antigos. Configure-o como requiredSpace apenas na API 17 acima. Por exemplo, use recursos de dimensão e substitua na pasta values-v17 resource.

A alteração foi introduzida via android.widget.CompoundButton.getCompoundPaddingLeft ();

kotucz
fonte
4
É a única resposta correta aqui - ele identifica o problema e fornece soluções simples, que usei com sucesso em vários aplicativos comerciais.
Madej
1
Como você obtém o buttonDrawable.width em XML ou o codifica?
Jared Kells
1
Consegui corrigir esse problema em um código antigo removendo android:background="@android:color/transparent".
Sebek
A resposta aceita é agradável e funcional, mas essa é simples e eficaz. Essa resposta deve ser aceita.
você precisa saber é o seguinte
27

Sim, você pode adicionar preenchimento adicionando preenchimento.

android:padding=5dp

Falmarri
fonte
4
Isso realmente funciona ... mais ou menos. Por um lado, apenas o paddingLeft é necessário, nem todo o preenchimento. No entanto, parece que o paddingLeft já está definido para um valor em torno de 40dp. Se eu definir> 40dp ele se afasta, se eu definir <40dp, ele se move sob a caixa de seleção. Vou marcar isso como correto e abrir outra pergunta, porque tenho preocupações com isso.
DougW 27/10/10
Bem, eu não tenho idéia sem ver seu layout.
Falmarri 27/10/10
sim, não está funcionando..particularmente dispositivo samsung tenho problema.
precisa
1
Adicionar preenchimento adicionando preenchimento parece legítimo!
Sermilion
21

Se você deseja um design limpo sem 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"/>

O truque é definir a cor como transparente android:drawableLefte atribuir um valor a android:drawablePadding. Além disso, a transparência permite que você use essa técnica em qualquer cor de fundo sem o efeito colateral - como incompatibilidade de cores.

ChuongPham
fonte
16

API 17 e acima, você pode usar:

android: paddingStart = "24dp"

API 16 e abaixo, você pode usar:

android: paddingLeft = "24dp"

Inmer
fonte
1
Resposta muito boa. Não consigo imaginar como o preenchimento dará espaço entre a caixa de seleção e o texto. Normalmente, o preenchimento esquerdo é esquerdo médio do componente.
Mohamed Ibrahim
14

No meu caso, resolvi esse problema usando o seguinte atributo CheckBox no XML:

*

android: paddingLeft = "@ dimen / activity_horizontal_margin"

*

Mohammad Zakaria
fonte
Resposta muito boa. Não consigo imaginar como o preenchimento dará espaço entre a caixa de seleção e o texto. Normalmente, o preenchimento esquerdo é esquerdo médio do componente.
Mohamed Ibrahim
13

Solução simples, adicione esta linha nas propriedades CheckBox , substitua 10dp pelo valor de espaçamento desejado

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

Eu não conheço caras, mas eu testei

<CheckBox android:paddingLeft="8mm" e move apenas o texto para a direita, não para o controle inteiro.

Isso combina comigo.

Tiago
fonte
1
Eu não tentei isso recentemente, por isso é possível que funcione em um dispositivo específico ou em uma versão mais recente do sistema operacional Android. Eu recomendo que você teste em configurações diferentes, porque isso definitivamente não funcionou no momento em que fiz essa pergunta.
DougW 14/09/11
Estou vendo isso se comportar de maneira diferente entre 2.3.3 e 4.2 (não tenho certeza de onde ocorreu a alteração).
Nate
Você quer dizer dp não mm?
precisa
10

Por que não apenas estender a caixa de seleção do Android para ter um melhor preenchimento? Dessa forma, em vez de precisar corrigi-lo no código toda vez que você usar o CheckBox, basta usar o CheckBox fixo.

Primeira caixa de seleção de extensão:

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 no seu xml, em vez de criar um CheckBox normal, crie o seu estendido

<com.whatever.CheckBoxWithPaddingFix
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello there" />
w.donahue
fonte
2
Você deve adicionar um 'if' para evitar fazer isso se OS> 4.2, porque no Jelly Bean eles "consertaram" isso.
Martin Marconcini
1
Na verdade> = 4,2 (17).
Aleks N.
6

Acabei de concluir sobre isso:

Substitua CheckBox e adicione este método se você tiver um drawable 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;
    }

}

ou isso se você usar o drawable do sistema:

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

}

Obrigado pela resposta :)

PaNaVTEC
fonte
4

Esse comportamento parece ter sido alterado no Jelly Bean. O truque paddingLeft adiciona preenchimento adicional, deixando o texto muito à direita. Alguém mais percebeu isso?

extremo
fonte
Obrigado pela atualização! Eu adicionei uma nota à minha resposta sobre isso.
DougW 27/03
4

Para espaço entre a marca de seleção e o texto, use:

android:paddingLeft="10dp"

Mas fica mais do que 10dp, porque a marca de seleção contém preenchimento (cerca de 5dp) ao redor. Se você deseja remover o preenchimento, consulte Como remover o preenchimento no Android CheckBox :

android:paddingLeft="-5dp"
android:layout_marginStart="-5dp"
android:layout_marginLeft="-5dp"
// or android:translationX="-5dp" instead of layout_marginLeft
CoolMind
fonte
2
<CheckBox
        android:paddingRight="12dip" />
AndrewKS
fonte
@AndrewKS - Testado. Como esperado, isso adiciona preenchimento a todo o controle, não entre a caixa de seleção e o texto.
DougW 27/10/10
Provavelmente é melhor ter o texto em um TextView separado.
AndrewKS
@AndrewKS - Má ideia para usabilidade. Desejo que o usuário possa tocar no texto e selecionar / desmarcar a caixa de seleção. Ele também quebra muitos recursos de acessibilidade, da mesma maneira que se você fizer isso em uma página da web.
DougW 27/10/10
Bad idea for usabilityNão, não é. Coloque a caixa de seleção e a exibição de texto em um layout linear e torne esse layout linear possível de tocar.
Falmarri 27/10/10
1
-1 Esta resposta não abordar a questão colocada na questão, que é sobre a diferença entre a imagem eo texto
David Laing
2

Se você tiver um seletor de imagem personalizado para a caixa de seleção ou o botão de opção, defina as mesmas propriedades de botão e plano de fundo, 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" />

Você pode controlar o tamanho da caixa de seleção ou do preenchimento dos botões de opção com a propriedade background.

Ilya Lisway
fonte
Não, você não precisa fazer isso. Isso não é aceitável se você tiver um plano de fundo personalizado diferente do glifo da caixa de seleção / botão de opção.
andr
2

somente você precisa ter um parâmetro no arquivo xml

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

Definir minHeight e minWidth como 0dpa solução mais limpa e direta para mim na API do Android 9 28:

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

Se você estiver criando botões personalizados, por exemplo, consulte o tutorial de alteração de aparência do checkbox

Depois, simplesmente aumente a largura de btn_check_label_background.9.png adicionando uma ou mais duas colunas de pixels transparentes no centro da imagem; deixe os marcadores de 9 patches como estão.

Keith Beardmore
fonte
1

O que eu fiz foi ter um TextViewe um CheckBoxdentro de um (relativo) Layout. O TextViewexibe o texto que eu quero que o usuário veja e CheckBoxnão possui nenhum texto. Dessa forma, eu posso definir a posição / preenchimento de CheckBoxonde eu quiser.

mbmc
fonte
1

Eu tive o mesmo problema com um Galaxy S3 mini (Android 4.1.2) e simplesmente fiz minha caixa de seleção personalizada estender AppCompatCheckBox em vez de CheckBox. Agora funciona perfeitamente.

Quentin G.
fonte
0

Você precisa obter o tamanho da imagem que está usando para adicionar seu preenchimento a esse tamanho. Nos internos do Android, eles obtêm o drawable que você especifica no src e usam seu tamanho posteriormente. Como é uma variável privada e não há getters, você não pode acessá-la. Além disso, você não pode obter o com.android.internal.R.styleable.CompoundButton e obter o drawable a partir daí.

Portanto, você precisa criar seu próprio estilo (ou seja, custom_src) ou adicioná-lo diretamente na sua implementação do 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
fonte
0

Como você provavelmente usa um seletor de drawable para sua android:buttonpropriedade, você precisa adicionar android:constantSize="true"e / ou especificar um drawable padrão 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>

Depois disso, você precisa especificar o android:paddingLeftatributo na sua caixa de seleção xml.

Contras:

No editor de layout, você encontrará o texto embaixo da caixa de seleção com a API 16 e abaixo; nesse caso, você poderá corrigi-lo criando sua classe de caixa de seleção personalizada, como sugerido, mas para o nível 16 da API.

Fundamentação:

é um bug, pois a StateListDrawable#getIntrinsicWidth()chamada é usada internamente, CompoundButtonmas pode retornar < 0valor se não houver estado atual e nenhum tamanho constante for usado.

Gianluca P.
fonte
0

Tudo o que você precisa fazer para superar esse problema é adicionar android:singleLine="true"ao checkBoxlayout xml do seu 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"/>

e nada de especial será adicionado programaticamente.

Muhammed Refaat
fonte
0

A imagem da caixa de seleção estava sobreposta quando usei meus próprios drawables do seletor, resolvi isso usando o código abaixo:

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

Agradecimentos a Alex Semeniuk

Jaiprakash Soni
fonte
0

Termino com esse problema alterando as imagens. Acabei de adicionar um fundo transparente extra em arquivos png. Esta solução funciona excelente em todas as APIs.

Leo Droidcoder
fonte
0

Talvez seja tarde demais, mas eu criei métodos utilitários para gerenciar esse problema.

Basta adicionar estes métodos aos seus utils:

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

E use assim:

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

ou assim:

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

Em vez de ajustar o texto para a caixa de seleção, fiz o seguinte e funcionou para mim em todos os dispositivos. 1) No XML, adicione a caixa de seleção e uma visualização de texto adjacentes uma após a outra; mantendo alguma distância. 2) Defina o tamanho do texto da caixa de seleção para 0sp. 3) Adicione texto relativo a essa exibição de texto ao lado da caixa de seleção.

Pankaj Deshpande
fonte
-3

<CheckBox android:drawablePadding="16dip" - O preenchimento entre as gavetas e o texto.

user1879118
fonte