0Pricing
Android Academy · Урок

Управление состоянием формы

Храните и обновляйте значения полей с помощью состояния

«Управление состоянием формы» — бесплатный урок Android Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Android Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Android Academy содержит 4 уроков всего.

От одного поля к форме

Одно текстовое поле — это просто. В настоящей форме их несколько: имя, адрес электронной почты, пароль, возможно, флажок. На этом уроке Вы узнаете, как удобно хранить и обновлять состояние всей формы в Jetpack Compose.

Если сделать всё правильно, проверка, отправка и предварительный просмотр станут простыми.

Несколько независимых состояний

Самый простой подход — по одному mutableStateOf на каждое поле. Каждое поле читает и обновляет свою часть состояния.

Для небольших форм с двумя или тремя полями этого вполне достаточно.

@Composable
fun LoginForm() {
    var email by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }

    Column {
        OutlinedTextField(email, { email = it }, label = { Text("Email") })
        OutlinedTextField(password, { password = it }, label = { Text("Password") })
    }
}

Группировка состояния в классе данных

По мере роста формы множество отдельных переменных становится неудобным. Более аккуратный вариант — представить всю форму как один неизменяемый data class.

Вы храните один фрагмент состояния с этим объектом и обновляете его с помощью copy().

data class SignUpState(
    val name: String = "",
    val email: String = "",
    val agreedToTerms: Boolean = false
)

Обновление с помощью copy()

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

Так модель состояния Compose остаётся предсказуемой: новый объект означает новый снимок, который запускает рекомпозицию.

var form by remember { mutableStateOf(SignUpState()) }

OutlinedTextField(
    value = form.name,
    onValueChange = { form = form.copy(name = it) },
    label = { Text("Name") }
)

Полная форма на основе data-класса

Здесь всей формой управляет один объект SignUpState. Каждое поле обновляет одно свойство с помощью copy().

Обратите внимание, как легко в любой момент получить значение всей формы: это просто form.

var form by remember { mutableStateOf(SignUpState()) }

Column {
    OutlinedTextField(
        value = form.name,
        onValueChange = { form = form.copy(name = it) },
        label = { Text("Name") }
    )
    OutlinedTextField(
        value = form.email,
        onValueChange = { form = form.copy(email = it) },
        label = { Text("Email") }
    )
}

Флажки и переключатели

Не все данные вводятся в виде текста. Checkbox или Switch работают так же: логическое значение и обратный вызов onCheckedChange.

Храните логическое значение в состоянии формы так же, как строку.

var form by remember { mutableStateOf(SignUpState()) }

Row(verticalAlignment = Alignment.CenterVertically) {
    Checkbox(
        checked = form.agreedToTerms,
        onCheckedChange = { form = form.copy(agreedToTerms = it) }
    )
    Text("I agree to the terms")
}

Вычисление значений из состояния

Одно из главных преимуществ единого источника состояния: значения можно вычислять на его основе, не сохраняя дополнительные переменные. Например, можно определить, готова ли форма к отправке.

Используйте derivedStateOf (или простое выражение), чтобы результат автоматически обновлялся при изменении формы.

var form by remember { mutableStateOf(SignUpState()) }

val canSubmit by remember {
    derivedStateOf {
        form.name.isNotBlank() &&
        form.email.isNotBlank() &&
        form.agreedToTerms
    }
}

Button(onClick = { /* submit */ }, enabled = canSubmit) {
    Text("Sign Up")
}

Сохранение состояния при изменении конфигурации

remember сохраняет состояние при рекомпозициях, но оно теряется при изменении конфигурации, например при повороте экрана. Чтобы сохранять простые значения при повороте, используйте rememberSaveable.

По умолчанию это работает с примитивными типами и типами Parcelable.

var email by rememberSaveable { mutableStateOf("") }

OutlinedTextField(
    value = email,
    onValueChange = { email = it },
    label = { Text("Email") }
)

Перенос состояния формы во ViewModel

Для любой формы, которая сложнее самой простой, храните состояние в ViewModel. Оно переживает изменения конфигурации, а логика интерфейса остаётся за пределами компонуемой функции.

Компонуемая функция считывает состояние и передаёт события, а ViewModel хранит актуальные данные.

class SignUpViewModel : ViewModel() {
    var state by mutableStateOf(SignUpState())
        private set

    fun onNameChange(value: String) {
        state = state.copy(name = value)
    }
}

Подключение ViewModel

В компонуемой функции получите ViewModel и свяжите каждое поле с его состоянием и обработчиком. Интерфейс останется простым и удобным для тестирования.

Это рекомендуемая структура для производственных форм.

@Composable
fun SignUpScreen(vm: SignUpViewModel = viewModel()) {
    OutlinedTextField(
        value = vm.state.name,
        onValueChange = vm::onNameChange,
        label = { Text("Name") }
    )
}

Чистый Kotlin: copy() в действии

Шаблон обновления с помощью copy() — это стандартное поведение data-классов Kotlin. Здесь он работает отдельно, чтобы Вы могли увидеть, как каждое обновление создаёт совершенно новый объект.

data class SignUpState(
    val name: String = "",
    val email: String = ""
)

fun main() {
    var state = SignUpState()
    state = state.copy(name = "Ada")
    state = state.copy(email = "ada@dev.io")
    println(state)
}

Быстрая проверка

Вы описываете форму как неизменяемый data class, хранящийся в состоянии. Как следует обновить отдельное поле?

Итоги

Вы научились управлять состоянием целых форм:

  • Небольшие формы: по одному mutableStateOf на каждое поле.
  • Большие формы: один неизменяемый data class, обновляемый с помощью copy().
  • Логические значения управляют Checkbox и Switch так же, как текст управляет полями.
  • Вычисляйте такие значения, как «можно отправить», вместо того чтобы сохранять их.
  • Используйте rememberSaveable для сохранения при повороте экрана, а ViewModel — для полноценных экранов.

Далее: проверка введённых данных и отображение понятных сообщений об ошибках.

Часто задаваемые вопросы

Урок «Управление состоянием формы» бесплатный?

Да — полный текст урока «Управление состоянием формы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Android Academy, подпишись на CoddyKit PRO. Курс Android Academy содержит 4 уроков всего.

Чему я научусь в уроке «Управление состоянием формы»?

Храните и обновляйте значения полей с помощью состояния Ты практикуешь Android Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Android Academy?

Предыдущий опыт не требуется. Android Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Управление состоянием формы»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Android Academy?

Да. Каждый урок Android Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. TextField и пользовательский ввод
  2. Управление состоянием формы
  3. Проверка ввода
  4. Параметры и действия клавиатуры
← Назад к Android Academy