Android - Odstępy między CheckBox a tekstem

256

Czy istnieje prosty sposób na dodanie dopełnienia między polem wyboru w kontrolce CheckBox a powiązanym tekstem?

Nie mogę po prostu dodać wiodących spacji, ponieważ moja etykieta jest wielowierszowa.

Na obecnym etapie tekst jest zbyt blisko pola wyboru: alternatywny tekst

DougW
źródło
1
Prostym rozwiązaniem byłoby użycie za TextViewpomocą drawableLefti użycie, drawablePaddingaby zwolnić miejsce na tekst. W kodzie po prostu przełączaj wybrane i niezaznaczone stany.
Muhammad Babar
Właśnie zauważyłem nowy atrybut xml o nazwie android: drawablePadding, który ma ustawiać odstępy między rysowalnym a tekstem. Nie próbowałem tego, ale myślę, że to rozwiązanie „po fakcie” google dla tego problemu.
Peri Hartman,

Odpowiedzi:

333

Nienawidzę odpowiadać na własne pytanie, ale w tym przypadku myślę, że muszę. Po sprawdzeniu, @Falmarri był na dobrej drodze ze swoją odpowiedzią. Problem polega na tym, że kontrolka CheckBox systemu Android korzysta już z właściwości android: paddingLeft, aby uzyskać tekst tam, gdzie jest.

Czerwona linia pokazuje wartość przesunięcia paddingLeft dla całego CheckBox

alternatywny tekst

Jeśli po prostu zastąpię to wypełnienie w moim układzie XML, spowoduje to popsucie układu. Oto, co robi ustawienie paddingLeft = "0":

alternatywny tekst

Okazuje się, że nie można tego naprawić w XML. Zrobisz to w kodzie. Oto mój fragment kodu ze zwiększonym zakresem wypełnienia o 10dp.

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

To daje następujące, gdzie zielona linia to wzrost wypełnienia. Jest to bezpieczniejsze niż zapisywanie wartości na stałe, ponieważ różne urządzenia mogą używać różnych rysunków dla pola wyboru.

alternatywny tekst

AKTUALIZACJA - jak ludzie ostatnio wspomnieli w odpowiedziach poniżej, to zachowanie najwyraźniej zmieniło się w Jelly Bean (4.2). Twoja aplikacja będzie musiała sprawdzić, na której wersji jest uruchomiona, i użyć odpowiedniej metody.

W wersji 4.3+ jest to po prostu ustawienie padding_left. Szczegółowe informacje można znaleźć w odpowiedzi htafoya.

DougW
źródło
108
Nie ma nic złego w udzieleniu odpowiedzi na własne pytanie - ktoś inny prawdopodobnie będzie miał ten problem w przyszłości, a ty po prostu udzieliłeś dobrej, wyczerpującej odpowiedzi.
AndrewKS
4
Co jest nie tak z samym ustawieniem paddingLeft="48sp"? Działa tutaj dobrze, nawet jeśli zmienię skalę i orientację. Twój kod podał mi nieprawidłowe wartości wypełnienia na liście elementów.
harpo
5
@harpo - Nie masz gwarancji, że różni producenci urządzeń nie użyją innej grafiki dla pola wyboru, co oznacza, że ​​zakodowane na stałe wypełnienie może uszkodzić układ wizualny na różnych urządzeniach. Ponieważ czytam bieżące wypełnienie i dodawanie do niego, nie będzie to problemem, ale musisz upewnić się, że zrobisz to tylko raz.
DougW
2
@Blundell - niekoniecznie. Android open source. Sprzedawca urządzeń może zastąpić zupełnie inną grafikę całkowicie innym rozmiarem. Z jakiegoś powodu uwielbiają robić takie rzeczy.
DougW,
2
Niestety nie możesz użyć tego rozwiązania w getView()niestandardowym adapterze (jeśli przetworzysz swoje widoki), ponieważ wypełnienie będzie się zwiększać w nieskończoność. Aby rozwiązać ten problem, musiałem użyć coś takiego: 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); }. A następnie użyj PADDINGdla każdego napełnionego CheckBox:check.setPadding(PADDING, check.getPaddingTop() ...
Alex Semeniuk
133

Biorąc pod uwagę odpowiedź @DougW, co robię, aby zarządzać wersją, jest prostsze, dodaję do mojego pola wyboru:

android:paddingLeft="@dimen/padding_checkbox"

gdzie dimen znajduje się w dwóch folderach wartości:

wartości

<resources>

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

</resources>

wartości-v17 (4.2 JellyBean)

<resources>

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

</resources>

Mam niestandardowy czek, użyj dps do najlepszego wyboru.

htafoya
źródło
2
To najlepsza jak dotąd odpowiedź. chociaż tak naprawdę powinno być values-v17tak, jak poprawka została wprowadzona w API 17 (zgodnie z niektórymi powyższymi postami)
lody
Idealna odpowiedź, tylko dla starszych apis (wartości / wymiary) ustawiłem padding_checkbox na 0dip (na API 10 margines jest już ogromny), a dla wartości-v17 10dip, jak sugeruje htafoya.
Yar
70

Użyj atrybutu android:drawableLeftzamiast android:button. Aby ustawić wypełnienie między rysowaniem a tekstem android:drawablePadding. Aby ustawić wysuwane użycie 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"
        />

wynik

Roman Trokhymets
źródło
1
Cześć, To miła metoda, ale zauważ, że dostaniesz dodatkowy lewy margines bcoz domyślnego obrazu pola wyboru .. wszelkie rozwiązania tego
Code_Life 23.01.2013
4
ustawiony android:background="@android:color/transparent"i lewy margines zniknie
madeuz
2
Powyższy kod działał idealnie dla moich przycisków opcji i jest spójny w granicach systemu operacyjnego 4.2. Dzięki!
gnichola
1
To powinno być ocenione znacznie wyżej. Jak powiedział @gnichola, działa to we wszystkich wersjach Androida i jest dość czystym rozwiązaniem. Utwórz styl i przypisz go do motywu w następujący <item name="android:checkboxStyle">@style/CheckBox</item> sposób : W ten sposób styl zostanie zdefiniowany tylko raz, a odniesienie do niego będzie możliwe tylko raz.
Rosomack
1
Ustaw także tło na null (lub coś niestandardowego), w przeciwnym razie Lollipop + uzyska efekt masywnego tętnienia koła obejmującego cały widok. Możesz użyć przycisku v21 do rysowania za pomocą tagów <ripple>, aby ponownie wprowadzić bardziej odpowiednie tętnienie.
Tom
34

Android 4.2 Jelly Bean (API 17) umieszcza tekst paddingLeft z przyciskuDrawable (ints prawa krawędź). Działa również w trybie RTL.

Przed 4.2 paddingLeft ignorował przyciskDrawable - został pobrany z lewej krawędzi widoku CompoundButton.

Możesz to rozwiązać za pomocą XML - ustaw paddingLeft na buttonDrawable.width + wymaganySpace na starszych androidach. Ustaw na wymagane Miejsce tylko w API 17 w górę. Na przykład użyj zasobów wymiarów i zastąp w folderze zasobów wartości-17.

Zmiana została wprowadzona za pośrednictwem android.widget.CompoundButton.getCompoundPaddingLeft ();

kotucz
źródło
4
To jedyna poprawna odpowiedź tutaj - wskazuje problem i zapewnia proste rozwiązania, które z powodzeniem zastosowałem w wielu aplikacjach komercyjnych.
madej
1
Jak uzyskać buttonDrawable.width w XML lub kodujesz go na stałe?
Jared Kells
1
Usunąłem ten problem w starym kodzie android:background="@android:color/transparent".
Sebek
Przyjęta odpowiedź jest miła i działa, ale ta jest prosta i skuteczna. Należy zaakceptować odpowiedź.
Reaz Murshed
27

Tak, możesz dodać dopełnienie, dodając dopełnienie.

android:padding=5dp

Falmarri
źródło
4
To faktycznie działa ... tak jakby. Po pierwsze, potrzebna jest tylko paddingLeft, a nie cała padding. Wygląda jednak na to, że paddingLeft ma już wartość około 40dp. Jeśli ustawię> 40dp, odsunie się, jeśli ustawię <40dp, przesunie się pod polem wyboru. Oznaczę to jako poprawne i otworzę kolejne pytanie, ponieważ mam obawy.
DougW
Nie mam pojęcia, nie widząc twojego układu.
Falmarri
tak nie działa .. szczególnie urządzenie Samsung Mam problem.
Ranjith Kumar
1
Dodawanie dopełnienia przez dodanie dopełnienia brzmi legalnie!
Kazanie
21

Jeśli chcesz mieć czysty design bez kodów, użyj:

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

Sztuką jest ustawienie koloru na przezroczysty android:drawableLefti przypisanie wartości android:drawablePadding. Ponadto przezroczystość pozwala na użycie tej techniki na dowolnym kolorze tła bez efektu ubocznego - np. Niedopasowanie kolorów.

ChuongPham
źródło
16

API 17 i wyżej, możesz użyć:

android: paddingStart = "24dp"

API 16 i poniżej, możesz użyć:

android: paddingLeft = "24dp"

Inmer
źródło
1
Bardzo dobra odpowiedź. Nie mogę sobie wyobrazić, jak wypełnienie zapewni odstęp między polem wyboru a tekstem. Zwykle Padding Left oznacza lewą stronę elementu.
Mohamed Ibrahim
14

W moim przypadku rozwiązałem ten problem za pomocą następującego atrybutu CheckBox w pliku XML:

*

android: paddingLeft = "@ dimen / activity_horizontal_margin"

*

Mohammad Zakaria
źródło
Bardzo dobra odpowiedź. Nie mogę sobie wyobrazić, jak wypełnienie zapewni odstęp między polem wyboru a tekstem. Zwykle Padding Left oznacza lewą stronę elementu.
Mohamed Ibrahim,
13

Proste rozwiązanie, dodaj ten wiersz do właściwości CheckBox , zastąp 10dp żądaną wartością odstępu

android:paddingLeft="10dp"
Naveed Ahmad
źródło
10

Nie znam facetów, ale testowałem

<CheckBox android:paddingLeft="8mm" i przesuwa tylko tekst w prawo, a nie całą kontrolę.

To mi odpowiada.

Tiago
źródło
1
Nie próbowałem tego ostatnio, więc z pewnością możliwe jest, że działa to na określonym urządzeniu lub nowszej wersji systemu operacyjnego Android. Gorąco polecam przetestowanie różnych konfiguracji, ponieważ zdecydowanie nie działało to w chwili, gdy zadałem to pytanie.
DougW,
Widzę, że zachowuje się inaczej w wersjach 2.3.3 i 4.2 (nie jestem pewien, gdzie pomiędzy zmianami nastąpiła).
Nate
Masz na myśli dp nie mm?
Chrispix
10

Dlaczego nie po prostu rozszerzyć Android CheckBox, aby zamiast tego mieć lepszą wypełnienie. W ten sposób zamiast konieczności poprawiania go w kodzie za każdym razem, gdy używasz CheckBox, możesz zamiast tego użyć po prostu ustalonego CheckBox.

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

Po drugie w swoim xml zamiast tworzenia normalnego CheckBox utwórz swój rozszerzony

<com.whatever.CheckBoxWithPaddingFix
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello there" />
w.donahue
źródło
2
Powinieneś dodać „if”, aby tego uniknąć, jeśli OS> 4.2, ponieważ w Jelly Bean „naprawili” to.
Martin Marconcini
1
W rzeczywistości> = 4,2 (17).
Aleks N.
6

Właśnie do tego doszedłem:

Zastąp CheckBox i dodaj tę metodę, jeśli masz niestandardowy program do rysowania:

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

}

lub to, jeśli używasz systemu do rysowania:

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

}

Dziękuję za odpowiedź :)

PaNaVTEC
źródło
4

Wygląda na to, że to zachowanie zmieniło się w Jelly Bean. Sztuczka paddingLeft dodaje dodatkowe dopełnienie, dzięki czemu tekst wygląda zbyt daleko w prawo. Czy ktoś to zauważył?

skrajny
źródło
Dziękuję za aktualizację! Do mojej odpowiedzi dodałem notatkę na ten temat.
DougW
4

Aby wstawić spację między znacznikiem wyboru a tekstem, użyj:

android:paddingLeft="10dp"

Ale staje się on większy niż 10dp, ponieważ znacznik wyboru zawiera dopełnienie (około 5dp) wokół. Jeśli chcesz usunąć wypełnienie, zobacz Jak usunąć wypełnienie wokół Androida CheckBox :

android:paddingLeft="-5dp"
android:layout_marginStart="-5dp"
android:layout_marginLeft="-5dp"
// or android:translationX="-5dp" instead of layout_marginLeft
CoolMind
źródło
2
<CheckBox
        android:paddingRight="12dip" />
AndrewKS
źródło
@AndrewKS - Testowane. Zgodnie z oczekiwaniami dodaje to dopełnianie do całej kontrolki, a nie między polem wyboru a tekstem.
DougW
Prawdopodobnie lepiej jest mieć tekst w osobnym TextView.
AndrewKS
@AndrewKS - Zły pomysł na użyteczność. Chcę, aby użytkownik mógł dotknąć tekstu i zaznaczyć / odznaczyć pole wyboru. Łamie także wiele funkcji ułatwień dostępu, tak samo jak na stronie internetowej.
DougW
Bad idea for usabilityNie, nie jest. Umieść zarówno pole wyboru, jak i widok tekstu w układzie liniowym i spraw, aby liniowy układ był dotykalny.
Falmarri
1
-1 Ta odpowiedź nie odnosi się do problemu postawionego w pytaniu, który dotyczy luki między obrazem a tekstem
David Laing
2

Jeśli masz niestandardowy selektor obrazu dla pola wyboru lub przycisku radiowego, musisz ustawić tę samą właściwość przycisku i tła, taką jak ta:

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

Możesz kontrolować rozmiar pola wyboru lub wypełnienia przycisku opcji za pomocą właściwości tła.

Ilya Lisway
źródło
Nie, nie musisz tego robić. Jest to niedopuszczalne, jeśli masz niestandardowe tło inne niż glif pola wyboru / radiobutton.
andr
2

tylko musisz mieć jeden parametr w pliku xml

android:paddingLeft="20dp"
tej shah
źródło
2

Ustawienie minHeight i minWidth 0dpbyło najczystszym i najprostszym rozwiązaniem dla mnie w systemie 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
źródło
1

Jeśli tworzysz niestandardowe przyciski, np. Zobacz zmianę wyglądu samouczka pola wyboru

Następnie po prostu zwiększ szerokość btn_check_label_background.9.png, dodając jedną lub dwie kolejne kolumny przezroczystych pikseli na środku obrazu; pozostaw znaczniki z 9 łatami takimi, jakie są.

Keith Beardmore
źródło
1

To, co zrobiłem, to posiadanie TextViewi CheckBoxwewnątrz (Relative) Layout. W TextViewwyświetla tekst, który chcę użytkownika, aby zobaczyć, a CheckBoxnie ma żadnego tekstu. W ten sposób mogę ustawić pozycję / wypełnienie w CheckBoxdowolnym miejscu.

mbmc
źródło
1

Miałem ten sam problem z Galaxy S3 mini (Android 4.1.2) i po prostu sprawiłem, że moje niestandardowe pole wyboru rozszerza AppCompatCheckBox zamiast CheckBox. Teraz działa idealnie.

Quentin G.
źródło
0

Musisz dodać rozmiar obrazu, którego używasz, aby dodać dopełnienie do tego rozmiaru. W urządzeniach wewnętrznych z systemem Android są one dostępne do rysowania, które określasz na src, a następnie używają jego rozmiaru. Ponieważ jest to zmienna prywatna i nie ma żadnych pobierających, do których nie można uzyskać dostępu. Ponadto nie możesz uzyskać com.android.internal.R.styleable.CompoundButton i stamtąd można pobrać.

Musisz więc stworzyć swój własny styl (np. Custom_src) lub możesz dodać go bezpośrednio w swojej implementacji 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
źródło
0

Ponieważ prawdopodobnie używasz selektora do rysowania dla swojej android:buttonwłaściwości, musisz dodać android:constantSize="true"i / lub określić domyślną rysowną w następujący sposób:

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

Następnie musisz określić android:paddingLeftatrybut w polu wyboru xml.

Cons:

W edytorze układu pojawi się tekst pod polem wyboru z interfejsem API 16 i niższym, w takim przypadku możesz to naprawić, tworząc niestandardową klasę pola wyboru, jak sugerowano, ale dla interfejsu API poziomu 16.

Racjonalne uzasadnienie:

jest to błąd, ponieważ StateListDrawable#getIntrinsicWidth()wywołanie jest używane wewnętrznie, CompoundButtonale może zwrócić < 0wartość, jeśli nie ma aktualnego stanu i nie jest używany stały rozmiar.

Gianluca P.
źródło
0

Wszystko, co musisz zrobić, aby rozwiązać ten problem, to dodać android:singleLine="true"do checkBoxukładu xml w Androidzie:

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

i nic specjalnego nie zostanie dodane programowo.

Muhammed Refaat
źródło
0

Obraz pola wyboru zachodził na siebie, gdy używałem własnych drawables z selektora, rozwiązałem to za pomocą poniższego kodu:

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

Dzięki Alex Semeniuk

Jaiprakash Soni
źródło
0

Kończę z tym problemem, zmieniając obrazy. Właśnie dodałem dodatkowe przezroczyste tło w plikach png. To rozwiązanie działa doskonale na wszystkich interfejsach API.

Leo Droidcoder
źródło
0

Może jest już za późno, ale stworzyłem narzędzia do zarządzania tym problemem.

Po prostu dodaj te metody do swoich narzędzi:

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

I użyj tego:

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

lub tak:

    // Be careful with this usage, because it sets padding in pixels, not in dp!
    ViewUtils.setCheckBoxOffsetPx(mAgreeTerms, 100f);
Ołeksandr
źródło
-1

Zamiast dostosowywać tekst dla Checkbox, zrobiłem następujące rzeczy i zadziałało to dla wszystkich urządzeń. 1) W XML dodaj pole wyboru i widok tekstu obok siebie; utrzymywanie dystansu. 2) Ustaw rozmiar pola wyboru na 0sp. 3) Dodaj względny tekst do tego widoku obok pola wyboru.

Pankaj Deshpande
źródło
-3

<CheckBox android:drawablePadding="16dip" - Wypełnienie między rysunkami a tekstem.

użytkownik1879118
źródło