Как настроить текстовые поля

TextField позволяет пользователям вводить и изменять текст. Существует два типа текстовых полей: на основе состояния и на основе значения. Выберите тип контента, который хотите посмотреть:

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

Функция

Текстовые поля на основе ценности

Текстовые поля на основе штата

Государственные льготы

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

Обновляет состояние текстового поля с помощью обратного вызова onValueChange. Вы несете ответственность за обновление value в своем штате на основе изменений, о которых сообщает onValueChange.

Явно использует объект TextFieldState для управления состоянием ввода текста (значение, выбор и композиция). Это состояние можно запомнить и поделиться им.

  • Обратный вызов onValueChange удален, поэтому вы не можете использовать асинхронные действия.
  • Состояние сохраняется при рекомпозиции, изменении конфигурации и завершении процесса.

Визуальное преобразование

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

Использует InputTransformation для изменения пользовательского ввода перед его фиксацией в состоянии и OutputTransformation для форматирования содержимого текстового поля без изменения базовых данных состояния.

  • Вам больше не нужно указывать сопоставление смещения между исходным необработанным текстом и преобразованным текстом с помощью OutputTransformation.

Ограничения на количество строк

Принимает singleLine: Boolean, maxLines: Int и minLines: Int для управления количеством строк.

Использует lineLimits: TextFieldLineLimits для настройки минимального и максимального количества строк, которое может занимать текстовое поле.

  • Устраняет неоднозначность при настройке ограничений на количество строк, предоставляя параметр lineLimits типа TextFieldLineLimits.

Защищенное текстовое поле

Н/Д

SecureTextField – это composable-функция, созданная на основе текстовых полей, которые зависят от состояния, и предназначенная для создания поля ввода пароля.

  • Позволяет оптимизировать безопасность на уровне кода и поставляется с предопределенным пользовательским интерфейсом с textObfuscationMode.

На этой странице описано, как реализовать TextField, настроить стиль ввода TextField и другие параметры TextField, например параметры клавиатуры и визуальное преобразование пользовательского ввода.

Выберите реализацию TextField

Существует два уровня реализации TextField:

  1. TextField – это реализация Material Design. Мы рекомендуем выбрать этот вариант, поскольку он соответствует рекомендациям Material Design.
  2. BasicTextField позволяет пользователям редактировать текст с помощью аппаратной или виртуальной клавиатуры, но не предоставляет никаких декоративных элементов, таких как подсказка или плейсхолдер.

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

Редактируемое текстовое поле со словом

OutlinedTextField(
    state = rememberTextFieldState(),
    label = { Text("Label") }
)

Редактируемое текстовое поле с фиолетовой рамкой и ярлыком.

Стиль TextField

У TextField и BasicTextField много общих параметров для настройки. Полный список для TextField доступен в исходном коде TextField. Ниже приведен неполный список полезных параметров.

  • textStyle
  • lineLimits

TextField(
    state = rememberTextFieldState("Hello\nWorld\nInvisible"),
    lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 2),
    placeholder = { Text("") },
    textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
    label = { Text("Enter text") },
    modifier = Modifier.padding(20.dp)
)

Многострочное текстовое поле с двумя редактируемыми строками и ярлыком

Мы рекомендуем использовать TextField вместо BasicTextField, если в вашем дизайне используется Material TextField или OutlinedTextField. Однако BasicTextField следует использовать при создании дизайнов, которым не нужны декорации из спецификации Material.

Настройте ограничения для строк

TextField composables support scrolling along a single axis. Поведение прокрутки определяется параметром lineLimits. TextField, настроенные для одной строки, прокручиваются по горизонтали, а многострочные TextField – по вертикали.

Используйте TextFieldLineLimits, чтобы выбрать подходящую конфигурацию для TextField:

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine
)

Однострочное текстовое поле с текстом

Конфигурация SingleLine имеет следующие характеристики:

  • Текст не переносится и не позволяет добавлять новые строки.
  • TextField всегда имеет фиксированную высоту.
  • Если текст не помещается, он прокручивается по горизонтали.

TextField(
    state = rememberTextFieldState("Hello\nWorld\nHello\nWorld"),
    lineLimits = TextFieldLineLimits.MultiLine(1, 4)
)

Многострочное текстовое поле с текстом

Конфигурация MultiLine имеет следующие характеристики:

  • Принимает два параметра: minHeightInLines и maxHeightInLines.
  • Высота текстового поля составляет не менее minHeightInLines.
  • Если текст не помещается, он будет перенесен.
  • Если текст не помещается, поле увеличивается до maxHeightInLines и появляется вертикальная прокрутка.

Стилизация ввода с помощью Brush API

Для более сложного оформления TextField можно использовать Brush API. В следующем разделе описывается, как использовать Brush, чтобы добавить цветной градиент к входным данным TextField.

Подробнее о том, как использовать Brush API для оформления текста…

Как реализовать цветные градиенты с помощью TextStyle

Чтобы при вводе текста в TextField использовался градиент цвета, задайте нужную кисть в качестве TextStyle для TextField. В этом примере мы используем встроенную кисть с linearGradient, чтобы увидеть эффект радужного градиента при вводе текста в TextField.

val brush = remember {
    Brush.linearGradient(
        colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Magenta)
    )
}
TextField(
    state = rememberTextFieldState(), textStyle = TextStyle(brush = brush)
)

Текст, который вводится в текстовое поле, с эффектом радужного градиента.
Рисунок 1. Радужный градиентный эффект для контента, связанного с TextField.

Управление состоянием текстового поля

TextField использует специальный класс хранилища состояния TextFieldState для контента и выбора. TextFieldState можно разместить в любом месте вашей архитектуры. TextFieldState предоставляет два основных свойства:

  • initialText – содержимое TextField.
  • initialSelection: указывает, где находится курсор или выделенный фрагмент.

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

Вы можете использовать TextFieldState(), чтобы поднять состояние в TextField. Для этого мы рекомендуем использовать функцию rememberTextFieldState(). rememberTextFieldState() создает экземпляр TextFieldState в composable-функции, обеспечивает запоминание объекта состояния и предоставляет встроенные функции сохранения и восстановления:

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

rememberTextFieldState может иметь пустой параметр или начальное значение, переданное для представления значения текста при инициализации. Если при последующей рекомпозиции передается другое значение, значение состояния не обновляется. Чтобы обновить статус после инициализации, вызовите методы редактирования в TextFieldState.

TextField(
    state = rememberTextFieldState(initialText = "Username"),
    lineLimits = TextFieldLineLimits.SingleLine,
)

Текстовое поле с текстом "Имя пользователя" внутри.
Рисунок 2. TextField с текстом "Имя пользователя".

Изменить текст с помощью TextFieldBuffer

TextFieldBuffer – это редактируемый текстовый контейнер, похожий по функциям на StringBuilder. Он содержит как текстовый контент, так и информацию о выделении.

Вы часто будете сталкиваться с TextFieldBuffer в качестве области получателя в таких функциях, как TextFieldState.edit, InputTransformation.transformInput или OutputTransformation.transformOutput. В этих функциях вы можете читать или обновлять TextFieldBuffer по мере необходимости. После этого изменения либо фиксируются в TextFieldState, либо передаются в конвейер рендеринга в случае OutputTransformation.

Для изменения содержимого буфера можно использовать стандартные функции редактирования, такие как append, insert, replace или delete. Чтобы изменить состояние выбора, задайте переменную selection: TextRange напрямую или используйте служебные функции, например placeCursorAtEnd или selectAll. Сам выбор представлен в виде TextRange, где начальный индекс включен, а конечный – исключен. Объект TextRange с одинаковыми значениями начала и конца, например (3, 3), обозначает позицию курсора без выделенных символов.

val phoneNumberState = rememberTextFieldState("1234567890")

TextField(
    state = phoneNumberState,
    keyboardOptions = KeyboardOptions(
        keyboardType = KeyboardType.Phone
    ),
    inputTransformation = InputTransformation.maxLength(10).then {
        if (!asCharSequence().isDigitsOnly()) {
            revertAllChanges()
        }
    },
    outputTransformation = OutputTransformation {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
)

Изменить текст в TextFieldState

Существует несколько методов, которые позволяют редактировать состояние непосредственно через переменную состояния:

  • edit – позволяет редактировать содержимое состояния и предоставляет функции TextFieldBuffer, чтобы вы могли использовать такие методы, как insert, replace, append и т. д.

    // Initial textFieldState text passed in is "I love Android"
    // textFieldState.text : I love Android
    // textFieldState.selection: TextRange(14, 14)
    textFieldState.edit { insert(14, "!") }
    // textFieldState.text : I love Android!
    // textFieldState.selection: TextRange(15, 15)
    textFieldState.edit { replace(7, 14, "Compose") }
    // textFieldState.text : I love Compose!
    // textFieldState.selection: TextRange(15, 15)
    textFieldState.edit { append("!!!") }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(18, 18)
    textFieldState.edit { selectAll() }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(0, 18)

  • setTextAndPlaceCursorAtEnd – удаляет текущий текст, заменяет его на указанный и устанавливает курсор в конце.

    textFieldState.setTextAndPlaceCursorAtEnd("I really love Android")
    // textFieldState.text : I really love Android
    // textFieldState.selection : TextRange(21, 21)

  • clearText: удаляет весь текст.

    textFieldState.clearText()
    // textFieldState.text :
    // textFieldState.selection : TextRange(0, 0)

Информацию о других функциях TextFieldState можно найти в справочнике по TextFieldState.

Изменение пользовательского ввода

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

Как фильтровать пользовательский ввод с помощью преобразования входных данных

Преобразование ввода позволяет фильтровать входные данные от пользователя. Например, если TextField принимает американский номер телефона, то в нем должно быть только 10 цифр. Результаты InputTransformation сохраняются в TextFieldState.

Для распространенных сценариев использования InputTransformation есть встроенные фильтры. Чтобы ограничить длину, вызовите InputTransformation.maxLength():

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine,
    inputTransformation = InputTransformation.maxLength(10)
)

Специальные преобразования входных данных

InputTransformation – это интерфейс с одной функцией. При реализации собственного класса InputTransformation необходимо переопределить метод TextFieldBuffer.transformInput:

class CustomInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
    }
}

Для номера телефона добавьте специальное преобразование ввода, которое разрешает вводить в TextField только цифры.

class DigitOnlyInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
        if (!asCharSequence().isDigitsOnly()) {
            revertAllChanges()
        }
    }
}

Преобразования входных данных в цепочке

Чтобы добавить несколько фильтров для текстового ввода, объедините InputTransformation с помощью функции расширения then. Фильтры применяются последовательно. Рекомендуем сначала применять фильтры с наиболее строгими критериями, чтобы не тратить время на преобразование данных, которые в итоге будут отфильтрованы.

TextField(
    state = rememberTextFieldState(),
    inputTransformation = InputTransformation.maxLength(6)
        .then(CustomInputTransformation()),
)

После добавления преобразований ввода поле TextField принимает не более 10 цифр.

Форматирование входных данных перед их отображением

OutputTransformation позволяют форматировать пользовательский ввод перед его отображением на экране. В отличие от InputTransformation, форматирование, выполненное с помощью OutputTransformation, не сохраняется в TextFieldState. Продолжая пример с номером телефона, вам нужно добавить скобки и дефисы в нужных местах:

Американский номер телефона, правильно отформатированный со скобками, дефисами и соответствующими индексами.
Рисунок 3. Американский номер телефона в правильном формате и с соответствующими индексами.

Это обновленный способ обработки VisualTransformation в TextField на основе ценности. Ключевое отличие заключается в том, что вам не нужно рассчитывать сопоставления смещений.

OutputTransformation – это интерфейс с одним абстрактным методом. Чтобы реализовать собственный класс OutputTransformation, необходимо переопределить метод transformOutput:

class CustomOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
    }
}

Чтобы отформатировать номер телефона, добавьте открывающую скобку в индекс 0, закрывающую скобку в индекс 4 и дефис в индекс 8 в OutputTransformation:

class PhoneNumberOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
}

Затем добавьте OutputTransformation в TextField:

TextField(
    state = rememberTextFieldState(),
    outputTransformation = PhoneNumberOutputTransformation()
)

Как работают преобразования

На следующей диаграмме показан поток от ввода текста к преобразованию и выводу:

Визуализация того, как входной текст преобразуется, прежде чем стать выходным текстом.
Рисунок 4. Диаграмма, показывающая, как входной текст преобразуется, прежде чем стать выходным текстом.
  1. Сигнал поступает из источника.
  2. Входные данные фильтруются через InputTransformation, который сохраняется в TextFieldState.
  3. Входные данные передаются через OutputTransformation для форматирования.
  4. Входные данные представлены в TextField.

Как настроить параметры клавиатуры

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

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

В класс KeyboardOptions добавлен новый логический параметр showKeyboardOnFocus, который используется специально для компонентов TextField, интегрированных с TextFieldState. Этот параметр определяет поведение виртуальной клавиатуры, когда фокус переходит на TextField не в результате прямого взаимодействия с пользователем (например, программно).

Если для KeyboardOptions.showKeyboardOnFocus задано значение true, виртуальная клавиатура не появляется автоматически, когда фокус переходит на TextField косвенно. В таких случаях пользователю нужно нажать на TextField, чтобы открыть клавиатуру.

Определите логику взаимодействия с клавиатурой

Командная кнопка на виртуальной клавиатуре Android позволяет пользователям взаимодействовать с приложением. Подробнее о том, как настроить командную кнопку…

Командная кнопка виртуальной клавиатуры (значок галочки), обведенная красным кругом.
Рисунок 5. Кнопка действия на виртуальной клавиатуре.

Чтобы определить, что происходит, когда пользователь нажимает на эту командную кнопку, используйте параметр onKeyboardAction. Этот параметр принимает необязательный функциональный интерфейс с именем KeyboardActionHandler. Интерфейс KeyboardActionHandler содержит один метод – onKeyboardAction(performDefaultAction: () -> Unit). Реализовав этот метод onKeyboardAction, вы можете добавить собственную логику, которая будет выполняться, когда пользователь нажимает командную кнопку на клавиатуре.

Для нескольких стандартных типов действий клавиатуры предусмотрены встроенные режимы работы по умолчанию. Например, если выбрать тип действия ImeAction.Next или ImeAction.Previous, фокус по умолчанию будет перемещаться на следующее или предыдущее поле ввода соответственно. Аналогично, командная кнопка, для которой задано значение ImeAction.Done, обычно закрывает виртуальную клавиатуру. Эти функции по умолчанию выполняются автоматически и не требуют указания KeyboardActionHandler.

Помимо действий по умолчанию, вы можете настроить собственные. Когда вы предоставляете KeyboardActionHandler, его метод onKeyboardAction получает функцию performDefaultAction. Вы можете вызвать эту функцию performDefaultAction() в любой точке вашей пользовательской логики, чтобы также запустить стандартное поведение по умолчанию, связанное с текущим действием IME.

TextField(
    state = textFieldViewModel.usernameState,
    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
    onKeyboardAction = { performDefaultAction ->
        textFieldViewModel.validateUsername()
        performDefaultAction()
    }
)

Этот фрагмент иллюстрирует распространенный вариант использования на экране регистрации с полем имени пользователя. Для этого поля в качестве командной кнопки на клавиатуре выбрано значение "ImeAction.Next". Это позволяет быстро и легко перейти к следующему полю пароля.

Помимо стандартной навигации, необходимо запустить фоновый процесс проверки имени пользователя, пока он вводит пароль. Чтобы сохранить стандартное поведение переключения фокуса, присущее ImeAction.Next, наряду с этой собственной валидацией, вызывается функция performDefaultAction(). Вызов performDefaultAction() неявно запускает базовую систему управления фокусом, чтобы переместить фокус на следующий подходящий элемент пользовательского интерфейса, сохраняя ожидаемый поток навигации.

Создайте поле для ввода пароля

SecureTextField – это composable-функция, созданная на основе текстовых полей, зависящих от состояния, и предназначенная для создания поля пароля. Для создания текстовых полей паролей рекомендуется использовать SecureTextField, так как он по умолчанию скрывает вводимые символы и отключает действия вырезания и копирования.

У SecureTextField есть textObfuscationMode, который управляет тем, как пользователь видит ввод символов. textObfuscationMode имеет следующие варианты:

  • Hidden – скрывает все входные данные. Режим работы по умолчанию на компьютерах.

    Защищенное текстовое поле, в котором вводимые символы скрыты.

  • Visible – показывает все входные данные.

    Защищенное текстовое поле, в котором видны вводимые символы.

  • RevealLastTyped: скрывает все символы, кроме последнего. Это режим работы по умолчанию на мобильных устройствах.

    Защищенное текстовое поле, в котором ненадолго показывается только последний введенный символ.

Дополнительные ресурсы