Освой Android играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

RadioButton и RadioGroup

Программное добавление переключателя
Добавление картинок к переключателю
Пример с переключателями">
Слушатель OnCheckedChangeListener
Метод clearCheck()
Метод getCheckedRadioButtonId(): Узнать выбранный элемент
Кот или муж?
Собственные стили
Собственный вид

Познакомимся с компонентом RadioButton, который находится в разделе Buttons. Главная особенность элемента состоит в том, что он не используется в одиночестве. Всегда должно быть два и более переключателя и только один из них может быть выбранным. Это похоже на кнопки на старых радиоприёмниках, когда нажимая на одну из кнопок, вы заставляете отключиться другую нажатую кнопку.

Компоненты RadioButton (переключатель) используются в составе контейнера RadioGroup. Обратите внимание на два момента. Первое - в контейнер RadioGroup можно включать не только RadioButton, но и другие элементы, например, TextView. Второе - переключатели работают в своём контейнере, т.е. если у вас два контейнера RadioGroup, то переключатели из одного контейнера не влияют на поведение переключателей второго контейнера.

Методы

Основным методом для переключателя является toggle(), который инвертирует состояние переключателя. Также представляют интерес методы isChecked(), который возвращает состояние кнопки, и setChecked(), изменяющий состояние кнопки в зависимости от параметра.


radioButton.setChecked(true); // программно устанавливаем статус у переключателя radioButton

Для уведомления о переходе положения переключателя в активное или неактивное состояние в результате определённых событий, нужно вызывать метод setOnCheckedChangeListener() с применением слушателя OnCheckedChangeListener.

Программное добавление переключателя

Получив ссылку на группу переключателей, можно добавить в неё ещё один переключатель (или другой элемент управления) через метод addView():


RadioGroup  radioGroup = findViewByld(R.id.radioGroup); 
RadioButton newRadioButton = new RadioButton(this); 
newRadioButton.setText("Рыжий"); 
radioGroup.addView(newRadioButton); 

Добавление картинок к переключателю

Вы можете добавить изображение в левой, правой, верхней и нижней части переключателя, используя либо определённые атрибуты XML или программно.

Через атрибут drawableRight и ему подобных:


<RadioButton
    android:id="@+id/radioButton"
    ...
    android:drawableRight="@drawable/ic_launcher"
    android:text="RadioButton" />

Программно через метод setCompoundDrawables(left, top, right, bottom):


radioButton.setCompoundDrawables(null, null, getResources().getDrawable(R.drawable.rightpic), null);

В этом примере мы указали только одно значение для правого края, остальным присвоили значение null. Можно одновременно задействовать все стороны переключателя.

Пример с переключателями

Создадим новую форму с четырьмя кнопками-переключателями, с помощью которых будем заливать фон приложения выбранным цветом. Сначала подготовим строковые ресурсы.


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Пример с переключателями (RadioButton)</string>
    <string name="current_pick">Текущий выбор</string>
    <string name="color_red">Красный</string>
    <string name="color_green">Зеленый</string>
    <string name="color_blue">Синий</string>
    <string name="color_gray">Серый</string>
</resources>

Создадим простейшую разметку на основе LinearLayout. Заполним форму текстовым блоком определённого цвета и присвоим ему текст "Текущий цвет". В нижней части формы расположим четыре цветных текстовых блока, а под ними четыре переключателя, с помощью которых мы будем менять цвет основного текстового блока.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/current_pick"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#666666"
        android:gravity="center"
        android:text="@string/current_pick"
        android:textColor="#ffffff" />

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/textViewRed"
            android:layout_width="match_parent"
            android:layout_height="20dp"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:background="#ff0000"
            android:text="@string/color_red"
            android:textColor="#660000" />

        <TextView
            android:id="@+id/textViewGreen"
            android:layout_width="match_parent"
            android:layout_height="20dp"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:background="#00ff00"
            android:text="@string/color_green"
            android:textColor="#006600" />

        <TextView
            android:id="@+id/textViewBlue"
            android:layout_width="match_parent"
            android:layout_height="20dp"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:background="#0000ff"
            android:text="@string/color_blue"
            android:textColor="#000066" />

        <TextView
            android:id="@+id/textViewGray"
            android:layout_width="match_parent"
            android:layout_height="20dp"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:text="@string/color_gray" />
    </LinearLayout>

    <RadioGroup
        android:id="@+id/radioGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#333333"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/radio_red"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="24dp"
            android:layout_weight="1" />

        <RadioButton
            android:id="@+id/radio_blue"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="24dp"
            android:layout_weight="1" />

        <RadioButton
            android:id="@+id/radio_green"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="24dp"
            android:layout_weight="1" />

        <RadioButton
            android:id="@+id/radio_gray"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="24dp"
            android:layout_weight="1"
            android:checked="true" />
    </RadioGroup>

</LinearLayout>

Обратите внимание, что элементы RadioButton помещаются в контейнер RadioGroup. Если теперь посмотреть на форму, то увидим одно большое серое поле. А снизу расположились в ряд четыре метки, а ещё ниже также в ряд расположились четыре переключателя. Причём последний серый переключатель имеет выбранный статус (android:checked="true").

Переходим к программной части. Добавляем слушатель для обработки щелчков на кнопках-переключателях.


package ru.alexanderklimov.radio;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.RadioButton;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView mInfoTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
		
        setContentView(R.layout.activity_main);

        mInfoTextView = findViewById(R.id.current_pick);

        RadioButton redRadioButton = findViewById(R.id.radio_red);
        redRadioButton.setOnClickListener(radioButtonClickListener);

        RadioButton greenRadioButton = (RadioButton)findViewById(R.id.radio_green);
        greenRadioButton.setOnClickListener(radioButtonClickListener);

        RadioButton blueRadioButton = findViewById(R.id.radio_blue);
        blueRadioButton.setOnClickListener(radioButtonClickListener);

        RadioButton grayRadioButton = findViewById(R.id.radio_gray);
        grayRadioButton.setOnClickListener(radioButtonClickListener);
    }

    View.OnClickListener radioButtonClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            RadioButton rb = (RadioButton)v;
            switch (rb.getId()) {
                case R.id.radio_red: mInfoTextView.setBackgroundColor(Color.parseColor("#ff0000"));
                    break;
                case R.id.radio_green: mInfoTextView.setBackgroundColor(Color.parseColor("#0000ff"));
                    break;
                case R.id.radio_blue: mInfoTextView.setBackgroundColor(Color.parseColor("#00ff00"));
                    break;
                case R.id.radio_gray: mInfoTextView.setBackgroundColor(Color.parseColor("#666666"));
                    break;

                default:
                    break;
            }
        }
    };
}

Запустим приложение и посмотрим, что у нас получилось. Пощёлкаем по переключателям и убеждаемся, что всё работает.

Переключатели RadioButton

Слушатель OnCheckedChangeListener

Показанный выше способ использует щелчок, так как переключатели можно рассматривать как кнопки. Но на самом деле у переключателей есть свой слушатель OnCheckedChangeListener. Я расположил в новом проекте RadioGroup с тремя RadioButton и написал простенький пример.


// Kotlin

// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.radio

import android.os.Bundle
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        val textView = findViewById<TextView>(R.id.textView)
        val radioGroup = findViewById<RadioGroup>(R.id.radioGroup)

        // radio group checked change listener
        radioGroup.setOnCheckedChangeListener { _, checkedId ->
            // get the radio group checked radio button
            findViewById<RadioButton>(checkedId)?.apply {
                // show the checked radio button's text in text view
                textView.text = text
            }
        }
    }
}

// Java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RadioGroup radioGroup = findViewById(R.id.radioGroup); radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId) { case -1: Toast.makeText(getApplicationContext(), "Ничего не выбрано", Toast.LENGTH_SHORT).show(); break; case R.id.radioButtonOne: Toast.makeText(getApplicationContext(), "Первый переключатель", Toast.LENGTH_SHORT).show(); break; case R.id.radioButtonTwo: Toast.makeText(getApplicationContext(), "Второй переключатель", Toast.LENGTH_SHORT).show(); break; case R.id.radioButtonThird: Toast.makeText(getApplicationContext(), "Третий переключатель", Toast.LENGTH_SHORT).show(); break; default: break; } } }); }

Этот способ намного удобней. Вам даже не нужно объявлять ссылки на переключатели и назначать им слушатели. Код получается более компактным.

Обратите внимание, что метод onCheckedChanged() принимает параметр RadioGroup, что позволяет применять один и тот же слушатель OnCheckedChangeListener() для нескольких групп переключателей. Вариант -1 сработает, когда группа переключателей будет сброшена в коде с помощью метода clearCheck().

Метод clearCheck()

Когда пользователь выберет любой из переключателей, то он уже не сможет снять с него отметку. Какой-нибудь из переключателей обязательно будет выбран в одном контейнере с ним. Единственный способ очистить все переключатели - программно вызвать метод clearCheck(), который относится к классу RadioGroup.


RadioGroup radioGroup;

// щелчок кнопки
public void onClick(View view) {
    // очистить все переключатели
	radioGroup.clearCheck();
}

Метод getCheckedRadioButtonId(): Узнать выбранный элемент

У RadioGroup есть также метод getCheckedRadioButtonId(), который позволяет узнать идентификатор выбранного переключателя. Можем узнать выбранный переключатель через нажатие кнопки.


// Kotlin
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.radio

import android.os.Bundle
import android.widget.Button
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        val textView = findViewById<TextView>(R.id.textView)
        val button = findViewById<Button>(R.id.button)
        val radioGroup = findViewById<RadioGroup>(R.id.radioGroup)

        button.setOnClickListener {
            val checkedRadioButtonId = radioGroup.checkedRadioButtonId

            when(checkedRadioButtonId){
                -1 -> {
                    textView.text = "Ничего не выбрано"
                }
                else -> {
                    // Найдём переключатель по его id
                    val selectedRadioButton = findViewById<RadioButton>(checkedRadioButtonId)
                    textView.text = selectedRadioButton.text
                }
            }
        }
    }
}

// Java public void onClick(View view) { int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); // Найдём переключатель по его id RadioButton myRadioButton = findViewById(checkedRadioButtonId); Toast.makeText(getApplicationContext(), myRadioButton.getText(), Toast.LENGTH_SHORT).show(); }

Также можно узнать индекс выбранного переключателя через метод indexOfChild():


OnCheckedChangeListener radioGroupOnCheckedChangeListener =
        new OnCheckedChangeListener(){

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {

        RadioButton checkedRadioButton = (RadioButton)radioGroup.findViewById(checkedId);
        int checkedIndex = radioGroup.indexOfChild(checkedRadioButton);
     
        textCheckedIndex.setText("checkedIndex = " + checkedIndex);
    }};

Кот или муж?

Теперь, когда вы познакомились с новым элементом, то вам не составит труда написать программу для нелёгкого выбора.

Выбираем кота

Разметка:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dip">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="" />

    <RadioGroup
        android:id="@+id/radioGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp">

        <RadioButton
            android:id="@+id/radioButtonHusband"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="true"
            android:text="Муж" />

        <RadioButton
            android:id="@+id/radioButtonKitten"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Котёнок" />
    </RadioGroup>

</LinearLayout>

И код:


// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.

package ru.alexanderklimov.radiobutton;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.RadioGroup;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView mInfoTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
		
        setContentView(R.layout.activity_main);
 
        mInfoTextView = findViewById(R.id.textView);

        RadioGroup radioGroup = findViewById(R.id.radioGroup);

        radioGroup.clearCheck();

        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId) {
                    case -1:
                        mInfoTextView.setText("");
                        break;
                    case R.id.radioButtonHusband:
                        mInfoTextView.setText("Подумайте ещё раз");
                        break;
                    case R.id.radioButtonKitten:
                        mInfoTextView.setText("Отличный выбор!");
                        break;
                }
            }
        });
    }
}

Переключатели RadioButton

Девушки, нужен ли вам такой муж? Если он не любит котиков, то будет ли любить вас? Возьмите лучше котёнка. Он клёвый.

Собственные стили

Если вы используете стандартный проект, то переключатели будут использовать цвета Material Design, в частности цвет colorAccent для кружочка с точкой.

В файле res/values/styles.xml добавим строки:


<style name="MyRadioButton" parent="Theme.AppCompat.Light">
    <item name="colorControlNormal">@android:color/holo_green_light</item>
    <item name="colorControlActivated">@android:color/holo_orange_dark</item>
</style>

Свойство colorControlNormal отвечает за окружность в невыбранном состоянии, а colorControlActivated за точку и окружность в выбранном состоянии.

Присваиваем созданный стиль атрибуту android:theme:


<RadioButton
    ...
    android:theme="@style/MyRadioButton"/>

Теперь цвета флажков изменились.

RadioButton Style

Собственный вид

Если вас не устраивает стандартный вид элементов RadioButton, то не составит никакого труда реализовать свои представления о дизайне.

В папке res/drawable создаём файл radiobutton_selector.xml:


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/radio_down" android:state_checked="true"/>
    <item android:drawable="@drawable/radio" android:state_checked="false"/>

</selector>

Также необходимо подготовить два изображения для двух состояний - выбран и не выбран.

Осталось прописать селектор в элементе RadioButton при размещении на экране (атрибут android:button):


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RadioGroup
        android:id="@+id/radioGroup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <RadioButton
            android:id="@+id/radio0"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:button="@drawable/radiobutton_selector"
            android:checked="true"
            android:text="RadioButton" />

        <RadioButton
            android:id="@+id/radio1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:button="@drawable/radiobutton_selector"
            android:text="RadioButton" />

        <RadioButton
            android:id="@+id/radio2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:button="@drawable/radiobutton_selector"
            android:text="RadioButton" />
    </RadioGroup>

</LinearLayout>

Готово! Можете запускать проект и проверять работу переключателей.

RadioButton

Дополнительное чтение

Запомнить состояние переключателей

Библиотеки

hoang8f/android-segmented-control - красивые переключатели

Пример на Kotlin есть в здесь

Реклама