RadioButton

Последнее обновление: 31.03.2024

Компонент RadioButton представляет переключатель или радиокнопку и служит для создания группы радиокнопок, из которых одномоментно можно выбрать только один переключатель. Этот компонент имеет следующие параметры:

@Composable
fun RadioButton(
    selected: Boolean,
    onClick: (() -> Unit)?,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    colors: RadioButtonColors = RadioButtonDefaults.colors(),
    interactionSource: MutableInteractionSource? = null
): Unit
  • selected: указывает, будет ли отмечена радиокнопка. Представляет значение Boolean. Если равен true, то радиокнопка отмечена.

  • onClick: представляет функцию типа () -> Unit, которая выполняется при нажатия на радиокнопку.

  • modifier: объект Modifier, который устанавливает для радиокнопки модификаторы

  • enabled: указывает, будет ли доступна радиокнопка. Представляет значение Boolean и по умолчанию равен true (то есть радиокнопка будет доступна).

  • interactionSource: объект MutableInteractionSource, который задает поток взаимодействий для радиокнопки. По умолчанию равен remember { MutableInteractionSource() }.

  • colors: объект RadioButtonColors, который задает цвета для радиокнопки. По умолчанию равен RadioButtonDefaults.colors().

Создадим группу из двух радиокнопок:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material3.RadioButton
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val state = remember { mutableStateOf(true) }
            Column(Modifier.selectableGroup())
            {
                RadioButton(
                    selected = state.value,
                    onClick = { state.value = true }
                )
                RadioButton(
                    selected = !state.value,
                    onClick = { state.value = false }
                )
            }
        }
    }
}

Для создании группы радиокнопок, которые рассматриваются именно как группа или единое целое, у контейнера - компонента Column или Row устанавливается модификатор Modifier.selectableGroup(). В данном случае радиокнопки помещаются в Column и соответственно будут располагаться в столбик:

Column(Modifier.selectableGroup())

Хотя также можно было бы расположить радиокнопки в строку, поместив в контейнер Row.

Для хранения состояния радиокнопок определяется переменная state, которая представляет тип MutableState<Boolean>:

val state = remember { mutableStateOf(true) }

С помощью свойства value получаем хранимое в переменной значение (true или false) и передаем его параметру selected радиокнопок:

selected = state.value

Но поскольку только одна радиокнопка одномоментно может быть выбрана, то другой радиокнопке передается противоположеное значение:

selected = !state.value

А в обработчике нажатия из параметра onClick изменяем данное значение:

onClick = { state.value = true }
RadioButton в Jetpack Compose и Kotlin в Android

Добавление текстовых меток к радиокнопкам

В примере выше мы видим, что для радиокнопок, как и для флажков, неопределяется никакой текстовой метки, которая несла бы самую минимальную информацию о радиокнопке. В этом случае необходимо самостоятельно комбинировать радиокнопку с текстовыми компонентами:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val state = remember { mutableStateOf(true) }
            Column {
                Text(text = if(state.value) {"Kotlin"} else {"Java"}, fontSize = 28.sp, modifier = Modifier.padding(10.dp))
                Column(Modifier.selectableGroup()) {
                    Row{
                        RadioButton(
                            selected = state.value,
                            onClick = { state.value = true }
                        )
                        Text("Kotlin", fontSize = 28.sp, modifier = Modifier.padding(4.dp))
                    }
                    Row{
                        RadioButton(
                            selected = !state.value,
                            onClick = { state.value = false }
                        )
                        Text("Java", fontSize = 28.sp, modifier = Modifier.padding(4.dp))
                    }
                }
            }
        }
    }
}

В данном случае, если state хранит true, то выбирается радиокнопка с языком Kotlin, если state хранит false, то выбирается радиокнока с языком Java.

Text и RadioButton в Jetpack Compose и Kotlin в Android

Обработка выбора варианта в группе радиокнопок

Выше приведенный пример довольно прост в том плане, что у нас только две радиокнопки - когда у одной кнопки параметр selected равен true, у другой равен false. В этом плане довольно просто задать логику переключения между радиокнопками. Однако что если у нас 3 и более переключателей? Рассмотрим следующий пример:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val languages = listOf("Kotlin", "Java", "Javascript", "Rust")
            val (selectedOption, onOptionSelected) = remember { mutableStateOf(languages[0]) }
            Column {
                Text(text = selectedOption, fontSize = 28.sp, modifier = Modifier.padding(10.dp))
                Column(Modifier.selectableGroup()) {
                    languages.forEach { text ->
                        Row( Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically)
                        {
                            RadioButton(
                                selected = (text == selectedOption),
                                onClick = { onOptionSelected(text) }
                            )
                            Text( text = text, fontSize = 24.sp )
                        }
                    }
                }
            }
        }
    }
}
выбор из группы RadioButton в Jetpack Compose и Kotlin в Android

В примере выше прежде всего все данные, которые будут представлять радиокнопки, помещаются в список languages:

val languages = listOf("Kotlin", "Java", "Javascript", "Rust")

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

Далее мы получаем объект MutableState<String>, который необходим для и отслеживания выбранного значения:

val (selectedOption, onOptionSelected) = remember { mutableStateOf(languages[0]) }

В функцию mutableStateOf() передается первый элемент из списка, то есть по умолчанию будет выбран первый элемент списка languages.

Однако мы не просто берем объект MutableState<String>, а раскладываем его на два компонента - selectedOption и onOptionSelected. Значение selectedOption будет представлять отслеживаемый объектом MutableState<String> элемент списка languages. А onOptionSelected - функция типа (String) -> Unit, которая будет вызываться при изменении значения в MutableState<String> и которая в качестве параметра будет получать новое значение.

Выбранный элемент из selectedOption выводится в верхний компонент Text:

Text(text = selectedOption, fontSize = 28.sp, modifier = Modifier.padding(10.dp))

Как и в примерах выше, чтобы задать группу выбираемых компонентов, для контейнера (в данном случае компонента Column) устанавливается модификатор selectableGroup:

Column(Modifier.selectableGroup()){ ........... }

Далее перебираем список languages с помощью функции forEach(), в которую передается функция, вызываемая для каждого перебираемого элемента:

 languages.forEach { text ->
	Row( Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically)
	{
		RadioButton(
			selected = (text == selectedOption),
            onClick = { onOptionSelected(text) }
		)
		Text( text = text, fontSize = 24.sp )
	}
}

Фактически в данном случае за каждой строкой закрепляется определенный элемент из списка languages. И радиокнопка является выбранный, если значение selectedOption совпадает со значением элемента из списка languages, закрепленным за данным компонентом Row:

selected = (text == selectedOption)

При нажатии на компонент срабатывает функция из параметра onClick, в которой вызывается функция onOptionSelected:

onClick = { onOptionSelected(text) }

В функции onOptionSelected передается закрепленный за компонентом Row элемент из списка languages, благодаря чему изменится выбранный элемент.

Выбор всей строки

Пример выше прекрасно работает, однако имеет один недостаток: чтобы выбрать радиокноку, необходимо пальцем попасть в этот небольшой кружок, который представляет радиокнопку. Было бы гораздо лучше, если бы мы могли нажать на любой место в строке, например, на текстовую метку, и тем самым выбрать радиокноку. Для этого изменим код следующим образом:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val languages = listOf("Kotlin", "Java", "Javascript", "Rust")
            val (selectedOption, onOptionSelected) = remember { mutableStateOf(languages[0]) }
            Column {
                Text(text = selectedOption, fontSize = 28.sp, modifier = Modifier.padding(10.dp))
                Column(Modifier.selectableGroup()) {
                    languages.forEach { text ->
                        Row( Modifier.fillMaxWidth()
                            .selectable(
                                selected = (text == selectedOption),
                                onClick = { onOptionSelected(text) }),
                            verticalAlignment = Alignment.CenterVertically)
                        {
                            RadioButton(
                                selected = (text == selectedOption),
                                onClick = { }
                            )
                            Text( text = text, fontSize = 24.sp )
                        }
                    }
                }
            }
        }
    }
}

Ключевым моментом здесь является установка модификатора Modifier.selectable:

 Row(
	Modifier.selectable(
		selected = (text == selectedOption),
		onClick = { onOptionSelected(text) }
),

Модификатор Modifier.selectable() делает компонент (в данном случае компонент Row) выделяемым. То есть мы можем выбрать не просто радиокнопку, а всю строку. В примере выше компонент Row является выбранным, если значение selectedOption совпадает со значением элемента из списка languages, закрепленным за данным компонентом Row:

selected = (text == selectedOption)

При нажатии на компонент срабатывает функция из параметра onClick, в которой вызывается функция onOptionSelected:

onClick = { onOptionSelected(text) }

В функции onOptionSelected передается закрепленный за компонентом Row элемент из списка languages, благодаря чему изменится выбранный элемент.

Кроме того, также надо настроить радиокнопки, которые выводятся в строке Row:

RadioButton(
	selected = (text == selectedOption),
	onClick = {}
)

Для выбора радиокнопки действует тот же алгоритм, что и для контейнера Row: радиокнопка выбрана, если текущий элемент из languages совпадает со значением selectedOption.

И поскольку выбор элемента обрабатывается в родительском контейнере Row, то нет смысла обрабатывать выбор элемента в радиокнопке, поэтому ее параметру onClick передается значение {} (по сути пустая функция).

Таким образом, внешне мы получим тот же визуальный интерфейс, только теперь для выделения радиокнопки достаточно нажать на любое место в строке.

Настройка цвета радиокнопок

За настройку цвета радиокнопок отвечает параметр colors компонента RadioButton. Для установки этого параметра можно использовать встроенную функцию RadioButtonDefaults.colors(), которая имеет следующее определение:

@Composable
public final fun colors(
    selectedColor: Color = RadioButtonTokens.SelectedIconColor.toColor(),
    unselectedColor: Color = RadioButtonTokens.UnselectedIconColor.toColor(),
    disabledSelectedColor: Color = RadioButtonTokens.DisabledSelectedIconColor             
        .toColor()             
        .copy(alpha = RadioButtonTokens.DisabledSelectedIconOpacity),
    disabledUnselectedColor: Color = RadioButtonTokens.DisabledUnselectedIconColor             
        .toColor()             
        .copy(alpha = RadioButtonTokens.DisabledUnselectedIconOpacity)
): RadioButtonColors

Таким образом, для отдельной радиокнопки мы можем установить 4 цвета:

  • selectedColor: цвет, когда кнопка выбрана

  • unselectedColor: цвет, когда кнопка не выбрана

  • disabledSelectedColor: цвет, когда кнопка выбрана, но не доступна

  • disabledUnselectedColor: цвет, когда кнопка не выбрана и не доступна

Например:

RadioButton(
    selected = (text == selectedOption),
    onClick = { },
    colors = RadioButtonDefaults.colors(selectedColor = Color.DarkGray, unselectedColor = Color.LightGray)
)
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850