Освой Android играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Программное добавление переключателя
Добавление картинок к переключателю
Пример с переключателями">
Слушатель 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;
}
}
};
}
Запустим приложение и посмотрим, что у нас получилось. Пощёлкаем по переключателям и убеждаемся, что всё работает.
Показанный выше способ использует щелчок, так как переключатели можно рассматривать как кнопки. Но на самом деле у переключателей есть свой слушатель 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(), который относится к классу RadioGroup.
RadioGroup radioGroup;
// щелчок кнопки
public void onClick(View view) {
// очистить все переключатели
radioGroup.clearCheck();
}
У 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;
}
}
});
}
}
Девушки, нужен ли вам такой муж? Если он не любит котиков, то будет ли любить вас? Возьмите лучше котёнка. Он клёвый.
Если вы используете стандартный проект, то переключатели будут использовать цвета 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, то не составит никакого труда реализовать свои представления о дизайне.
В папке 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>
Готово! Можете запускать проект и проверять работу переключателей.
Запомнить состояние переключателей
hoang8f/android-segmented-control - красивые переключатели
Пример на Kotlin есть в здесь