Android - пробіл між CheckBox та текстом


256

Чи є простий спосіб додати прокладку між прапором у контролі CheckBox та пов'язаним текстом?

Я не можу просто додати провідні пробіли, оскільки мітка є багаторядковою.

Так, текст є занадто близьким до прапорця: alt текст


1
Просте рішення буде з допомогою TextViewз drawableLeftі використовувати , drawablePaddingщоб дати місце для тексту. У коді просто перемикайте вибрані та невибрані стани.
Мухаммед Бабар

Щойно я помітив новий атрибут xml під назвою android: dravablePadding, який повинен встановити проміжок між рисувальним та текстом. Я не пробував цього, але думаю, що це проблема "go-gole" для цієї проблеми.
Peri Hartman

Відповіді:


333

Я ненавиджу відповідати на власне запитання, але в цьому випадку я думаю, що мені потрібно. Перевіривши це, @Falmarri був на правильному шляху зі своєю відповіддю. Проблема полягає в тому, що контроль CheckBox Android вже використовує властивість android: paddingLeft, щоб отримати текст там, де він є.

Червона лінія показує значення зміщення paddingLeft для всієї CheckBox

alt текст

Якщо я просто перекрию цю підкладку в моєму макеті XML, це зіпсує макет. Ось що робить paddingLeft = "0":

alt текст

Виявляється, ви не можете виправити це в XML. Ви це зробите в коді. Ось мій фрагмент із твердим кодом, що збільшує 10dp.

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

Це дає вам наступне, де зеленою лінією є збільшення підкладки. Це безпечніше, ніж значення жорсткого кодування, оскільки різні пристрої можуть використовувати різні чертежі для прапорця.

alt текст

ОНОВЛЕННЯ - Як люди нещодавно згадували у відповідях нижче, ця поведінка, очевидно, змінилася в Jelly Bean (4.2). Ваш додаток повинен перевірити, на якій версії працює його програма, і використовувати відповідний метод.

Для версії 4.3+ це просто встановлення padding_left. Деталі див. У відповіді htafoya.


108
Нічого поганого у відповіді на власне питання - хтось інший, мабуть, матиме цю проблему в майбутньому, і ви просто дали хорошу, всебічну відповідь.
AndrewKS

4
Що не так з просто налаштуванням paddingLeft="48sp"? Тут чудово працює, навіть якщо я міняю масштаб та орієнтацію. Ваш код дав мені помилкові значення прокладки над списком елементів.
гарпо

5
@harpo - Ви не маєте гарантій, що різні виробники пристроїв не використовуватимуть різну графіку для прапорця, тобто ваші жорстко закодовані накладки можуть порушити ваш візуальний макет на різних пристроях. Оскільки я читаю поточну підкладку і додаю до неї, це не буде проблемою, але вам доведеться переконатися, що ви це зробите лише один раз.
DougW

2
@Blundell - Не обов’язково. Відкритий код Android. Постачальник пристроїв може замінити зовсім іншу графіку абсолютно різними розмірами. Вони люблять робити такі речі чомусь.
DougW

2
На жаль, ви не можете використовувати це рішення у getView()користувальницькому адаптері (якщо ви переробляєте перегляди), оскільки прокладки будуть нескінченно збільшуватися. Щоб усунути цю проблему , мені довелося використовувати що - щось на зразок цього: 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); }. А потім використовувати PADDINGдля кожного надувного я CheckBox:check.setPadding(PADDING, check.getPaddingTop() ...
Олексій Семенюк

133

З огляду на @DougW відповідь, що я роблю, щоб керувати версією, простіше, я додаю до перегляду прапорець:

android:paddingLeft="@dimen/padding_checkbox"

де розмір знаходиться у двох папках значень:

значення

<resources>

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

</resources>

значення-v17 (4,2 JellyBean)

<resources>

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

</resources>

У мене є спеціальна перевірка, використовуйте dps для вашого найкращого вибору.


2
Це найкраща відповідь поки що. хоча, це справді має бути values-v17так, як виправлення було введено в API 17 (згідно з деякими публікаціями вище)
icecreamman

Ідеальна відповідь, лише для старих apis (значень / розмірів) я встановив padding_checkbox на 0dip (на API 10 запас вже величезний) і для значень-v17 10dip, як запропонував htafoya.
Яр

70

Використовуйте атрибут android:drawableLeftзамість android:button. Щоб встановити прокладку між текстовим та текстовим використанням android:drawablePadding. Для позиціонування шаблону використання 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"
        />

результат


1
Привіт, це хороший метод, але зауважте, що у вас з'являється додаткова ліва межа bcoz за замовчуванням зображення прапорця .. будь-які рішення для цього
Code_Life

4
встановлений android:background="@android:color/transparent"і лівий запас зникне
madeuz

2
Код, описаний вище, чудово працював для моїх радіо кнопок, і він відповідає всій межі 4.2 ОС. Дякую!
gnichola

1
Це слід класифікувати набагато вище. Як сказав @gnichola, це працює в Android-версіях і є досить чистим рішенням. Створіть стиль та призначте його у своїй темі так: <item name="android:checkboxStyle">@style/CheckBox</item> Таким чином, ви визначили стиль один раз і посилаєтесь лише один раз.
Росомак

1
Також встановіть фон на null (або щось на замовлення), інакше льодяник + отримує ефект масивного пульсації кола, що охоплює весь вид. Ви можете скористатися кнопкою v21 для малювання, використовуючи теги <ripple>, щоб повернути більш підходящу пульсацію.
Том

34

Android 4.2 Jelly Bean (API 17) ставить текстові накладки ліворуч від кнопкиDravable (ints right edge). Він також працює в режимі RTL.

Перед 4.2 paddingLeft ігнорував кнопкуDravable - це було зроблено з лівого краю подання CompoundButton.

Ви можете вирішити це за допомогою XML - встановіть paddingLeft на buttonDravable.width + mustSpace на старих андроїдах. Встановіть його на mustSpace лише в API 17 up. Наприклад, використовуйте параметри ресурсів та замініть параметр у папці значень-v17.

Зміна була введена через android.widget.CompoundButton.getCompoundPaddingLeft ();


4
Тут єдина правильна відповідь - вона визначає проблему та пропонує прості рішення, які я успішно використовував у кількох комерційних додатках.
madej

1
Як отримати buttonDravable.width у XML чи ти жорстко кодуєш його?
Джаред Келлс

1
Мені вдалося виправити цю проблему в старому коді, видаливши android:background="@android:color/transparent".
Себек

Прийнята відповідь є приємною та робочою, але ця проста та ефективна. На це слід прийняти відповідь.
Реаз Муршед

27

Так, ви можете додати прокладку, додавши прокладку.

android:padding=5dp


4
Це насправді працює ... подібне. Для одного потрібен лише paddingLeft, а не весь padding. Однак схоже, що paddingLeft вже встановлений у значення близько 40dp. Якщо я встановив його> 40dp, він відсувається, якщо я встановив його <40dp, він переміститься під прапором. Я відзначу це правильним і відкрию ще одне питання, тому що у мене є проблеми.
DougW

Ну я поняття не маю, не бачивши вашого макета.
Фальмарі

так, не працює .. Особливо з пристроєм Samsung у мене проблема.
Ранджіт Кумар

1
Додавання прокладки шляхом додавання звукових сигналів законно!
Сермиліон

21

Якщо ви хочете охайний дизайн без кодів, використовуйте:

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

Трюк - встановити прозорий колір android:drawableLeftі призначити значення для android:drawablePadding. Також прозорість дозволяє використовувати цю техніку для будь-якого кольору фону без побічного ефекту - як невідповідність кольорів.


16

API 17 і вище, ви можете використовувати:

android: paddingStart = "24dp"

API 16 і нижче, ви можете використовувати:

android: paddingLeft = "24dp"


1
Дуже гарна відповідь. Я не уявляю, як накладка дасть пробіл між прапором і текстом. Зазвичай прокладка ліворуч від лівого компонента.
Мохаммед Ібрагім

14

У моєму випадку я вирішив цю проблему, використовуючи наступний атрибут CheckBox у XML:

*

android: paddingLeft = "@ dimen / activity_horizontal_margin"

*


Дуже гарна відповідь. Я не уявляю, як накладка дасть пробіл між прапором і текстом. Зазвичай прокладка ліворуч від лівого компонента.
Мохаммед Ібрагім

13

Просте рішення, додайте цей рядок у властивості CheckBox , замініть 10dp на потрібне значення інтервалу

android:paddingLeft="10dp"

10

Хлопці не знаю, але я протестував

<CheckBox android:paddingLeft="8mm" і лише переміщує текст праворуч, не весь контроль.

Мені це добре підходить.


1
Я нещодавно не пробував цього, тому, безумовно, можливо, що це працює на певному пристрої чи новій версії ОС Android. Настійно рекомендую протестувати різні налаштування, оскільки це, безумовно, не спрацювало в той час, коли я задав це питання.
DougW

Я бачу, як це поводиться по-різному між 2.3.3 та 4.2 (не впевнений, де між змінами відбулася зміна).
Нейт

Ви маєте на увазі dp не мм?
Кріспікс

10

Чому б просто не розширити Android CheckBox, щоб натомість мати кращі накладки. Таким чином, замість того, щоб фіксувати його в коді кожного разу, коли ви використовуєте CheckBox, ви можете просто використовувати фіксований CheckBox замість цього.

Перший розширений 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));
    }
}

По-друге, у вашому xml замість створення звичайного CheckBox створіть розширений

<com.whatever.CheckBoxWithPaddingFix
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello there" />

2
Ви повинні додати "if", щоб уникнути цього, якщо OS> 4.2, тому що в Jelly Bean вони "виправили" це.
Мартін Маркончіні

1
Власне> = 4,2 (17).
Алекс Н.

6

Я щойно зробив висновок з цього приводу:

Замініть CheckBox і додайте цей метод, якщо у вас є спеціальний малюнок:

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

}

або це, якщо ви користуєтеся системою, що перетягується:

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

}

Дякую за відповідь :)


4

Ця поведінка, схоже, змінилася в Jelly Bean. Трюк paddingLeft додає додаткові накладки, завдяки чому текст виглядає занадто вправо. Хтось ще помітив це?


Дякуємо за оновлення! Я додав замітку до своєї відповіді з цього приводу.
DougW

4

Пробіл між галочкою та текстом використовується:

android:paddingLeft="10dp"

Але він стає більше 10dp, тому що галочка містить набивання (близько 5dp) навколо. Якщо ви хочете видалити прокладки, перегляньте розділ Як видалити прокладки навколо Android CheckBox :

android:paddingLeft="-5dp"
android:layout_marginStart="-5dp"
android:layout_marginLeft="-5dp"
// or android:translationX="-5dp" instead of layout_marginLeft

2
<CheckBox
        android:paddingRight="12dip" />

@AndrewKS - Тестується. Як і очікувалося, це додає набивання на весь елемент керування, а не між прапорцем і текстом.
DougW

Вам, напевно, краще мати текст в окремому TextView.
AndrewKS

@AndrewKS - погана ідея щодо зручності використання. Я хочу, щоб користувач міг торкнутися тексту та встановити / зняти прапорець. Це також порушує багато функцій доступності, так само, як якщо б ви це робили на веб-сторінці.
DougW

Bad idea for usabilityНі це не так. Поставте і прапорець, і перегляд тексту в лінійному макеті, і зробіть це лінійне розташування дотичним.
Falmarri

1
-1 Ця відповідь не стосується питання, поставленого у питанні, що стосується розриву між зображенням та текстом
Девід Лаїнг

2

Якщо у вас є спеціальний перемикач зображень для прапорця або радіо кнопки, ви повинні встановити таку ж властивість кнопок і фонів, як ця:

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

Ви можете керувати розміром прапорця або набивання радіо кнопок із властивістю фону.


Ні, не потрібно цього робити. Це не прийнятно, якщо у вас є власне тло, яке відрізняється від гліфів прапорця / радіо кнопки.
andr

2

тільки вам потрібно мати один параметр у файлі xml

android:paddingLeft="20dp"

2

Налаштування minHeight та minWidth 0dpбуло найчистішим та найпростішим рішенням для 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" />

1

Якщо ви створюєте спеціальні кнопки, наприклад, див. Підручник із зміни вигляду

Потім просто збільшити ширину btn_check_label_background.9.png, додавши ще один або два стовпчики прозорих пікселів у центрі зображення; залиште 9-латові маркери такими, якими вони є.


1

Те, що я зробив, - це те, що є TextViewі CheckBoxвсередині (Відносно) Layout. В TextViewвідображає текст , який я хочу, щоб користувач бачив, і CheckBoxне має будь - яких текст. Таким чином, я можу встановити положення / накладку CheckBoxкуди завгодно.


1

У мене була така ж проблема з Galaxy S3 mini (android 4.1.2), і я просто зробив свій власний прапорець розширити AppCompatCheckBox замість CheckBox. Зараз це прекрасно працює.


0

Вам потрібно отримати розмір зображення, яке ви використовуєте, щоб додати ваші набивки до цього розміру. У внутрішніх системах Android вони отримують вказаний у src графічний малюнок, а потім використовують його розмір. Оскільки це приватна змінна, і немає користувачів, до яких ви не можете отримати доступ. Крім того, ви не можете отримати com.android.internal.R.styleable.CompoundButton і отримати звідти доступний файл.

Отже, вам потрібно створити свій власний стиль (наприклад, custom_src) або додати його безпосередньо у вашу реалізацію 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;
    }
}

0

Оскільки ви, ймовірно, використовуєте селектор, що витягується, для вашої android:buttonвласності, вам потрібно додати android:constantSize="true"та / або вказати типовий параметр для малювання, як це:

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

Після цього потрібно вказати android:paddingLeftатрибут у вашому прапорці xml.

Мінуси:

У редакторі макета ви вкажете текст, який знаходиться під прапором з api 16 і нижче, і в цьому випадку ви можете це виправити, створивши для вас спеціальний клас прапорця, як запропоновано, але для api рівня 16.

Обгрунтування:

це помилка, оскільки StateListDrawable#getIntrinsicWidth()виклик використовується внутрішньо, CompoundButtonале він може повернути < 0значення, якщо немає поточного стану та не використовується постійний розмір.


0

Все, що вам потрібно зробити, щоб подолати цю проблему - це додати android:singleLine="true"до checkBoxвашого xml-макета 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"/>

і нічого особливого не буде додано програмно.


0

Зображення прапорця перекривалося, коли я використовував власні малюнки з селектора, я вирішив це за допомогою наведеного нижче коду:

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

Дякую Олексію Семенюку


0

Я закінчую це питання, змінюючи зображення. Просто додано додатковий прозорий фон у png-файлах. Це рішення чудово працює на всіх API.


0

Можливо, вже пізно, але я створив корисні методи управління цією проблемою.

Просто додайте ці методи до своїх утиліт:

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

І використовуйте так:

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

або так:

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

-1

Замість того, щоб коригувати текст для Checkbox, я зробив наступне, і це працювало для мене на всіх пристроях. 1) у XML додайте прапорець та перегляд тексту, що прилягають один до одного; зберігаючи деяку відстань. 2) Установіть розмір тексту прапорця на 0sp. 3) Додайте відносний текст до цього перегляду тексту поруч із прапором.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.