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

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

Шкодим

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

Compose: TextField

10-й курс/Закрытая зона

Обновлено 31.07.2023, 20.02.2024, 02.05.2024, 2 мая 2025

TextField

Функция TextField позволяет создать стандартное текстовое поле для ввода текста, знакомое нам по EditText.

Определение функции.


@OptIn(markerClass = {androidx. compose. material3.ExperimentalMaterial3Api::class})
@Composable
public fun TextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle. current,
    label: @Composable() (() -> Unit)? = null,
    placeholder: @Composable() (() -> Unit)? = null,
    leadingIcon: @Composable() (() -> Unit)? = null,
    trailingIcon: @Composable() (() -> Unit)? = null,
    prefix: @Composable() (() -> Unit)? = null,
    suffix: @Composable() (() -> Unit)? = null,
    supportingText: @Composable() (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation. None,
    keyboardOptions: KeyboardOptions = KeyboardOptions. Default,
    keyboardActions: KeyboardActions = KeyboardActions. Default,
    singleLine: Boolean = false,
    maxLines: Int = if (singleLine) 1 else Int. MAX_VALUE,
    minLines: Int = 1,
    interactionSource: MutableInteractionSource? = null,
    shape: Shape = TextFieldDefaults. shape,
    colors: TextFieldColors = TextFieldDefaults. colors()
): Unit

Создадим текстовое поле для ввода текста. Для простого примера ограничимся параметрами label и placeholder (при желании параметры можно убрать, чтобы оставить только пустое поле без украшений).


@Composable
fun Content(modifier: Modifier = Modifier) {

    Column(
        modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Top
    ) {
        var text by remember { mutableStateOf("") } // пустая строка

        TextField(
            value = text,
            onValueChange = { text = it },
            label = { Text("Введите имя кота") },
            placeholder = { Text(text = "Барсик") },
            modifier = modifier.padding(4.dp)
        )
    }
}

Если вам нужно ввести заранее текст, то просто добавьте его в text.


var text by remember { mutableStateOf("Здесь написано Кот") }

Ниже показано текстовое поле в трёх различных состояниях:

  • не в фокусе
  • в фокусе (появляется подсказка-placeholder)
  • после ввода символов пользователем

TextField

Текущий текст хранится в параметре value. При вводе символов срабатывает метод обратного вызова onValueChange(), который позволяет получить новый текст.

Длину и высоту поля можно установить через Modifier.width().height().


modifier = Modifier.fillMaxWidth()

modifier = Modifier
    .width(250.dp)
    .wrapContentHeight(align = Alignment.CenterVertically)

modifier = Modifier
    .requiredWidth(315.dp)
    .height(150.dp)

modifier = Modifier
    .fillMaxWidth(0.8F)
    .height(100.dp)

Задать другую форму для текстового поля можно через модификатор border.


@Composable
fun Content(modifier: Modifier = Modifier) {
    Column(
        modifier
            .background(Color(0xFFEDEAE0))
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(80.dp)
    ) {
        // Spacer(modifier = modifier.height(60.dp))

        var text by remember { mutableStateOf(TextFieldValue()) }
        val gradient = listOf(Color.Red, Color.Yellow, Color.Green)

        TextField(
            value = text,
            onValueChange = { text = it },
            modifier = modifier
                .padding(4.dp)
                .border(
                    border = BorderStroke(
                        brush = Brush.linearGradient(gradient),
                        width = 2.dp
                    ),
                    shape = CutCornerShape(12.dp)
                ),
            label = {
                Text(text = "Введите имя кота")
            },
            placeholder = { Text(text = "Барсик") },
        )
    }
}

Если запустить этот пример, то можно увидеть, полоску для индикации получения фокуса. Как её убрать - в примере ниже.

TextField border

colors

В параметре colors можно настраивать различные цвета (более 40 параметров!). Изменим цвет фона и текста.


TextField(
    ...
    modifier = Modifier.padding(4.dp),
    colors = TextFieldDefaults.colors(
        focusedContainerColor = Color.Magenta,
        focusedTextColor = Color.Green
    )
)

У текстового поля внизу идёт тонкая полоска для индикации получения фокуса. Можем убрать её, сделав прозрачной. Либо можете установить свои цвета, чтобы подчеркнуть индивидуальность.


colors = TextFieldDefaults.colors(
    focusedIndicatorColor = Color.Transparent,
    unfocusedIndicatorColor = Color.Transparent
)

Для примера с параметром isError (см. ниже) можно применить цвета для индикации ошибки.


colors = TextFieldDefaults.textFieldColors(
    errorIndicatorColor = Color.Magenta,
    errorCursorColor = Color.Magenta,
    errorLabelColor = Color.Magenta
)

leadingIcon/trailingIcon

В начале и в конце текстового поля можно поместить значок.


@Composable
fun Content(modifier: Modifier = Modifier) {
    Column(
        modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Top
    ) {
        var text by remember { mutableStateOf("") }


        TextField(
            value = text,
            onValueChange = { text = it },
            modifier = modifier.padding(4.dp),
            label = { Text("Купить для кота") },
            leadingIcon = {
                Icon(
                    imageVector = Icons.Filled.Star,
                    contentDescription = null,
                    tint = Color.Magenta
                )
            },
            trailingIcon = {
                // По аналогии
            }
        )
    }
}

В Compose есть готовый компонент SearchBar, но вы можете самостоятельно создать похожий элемент, добавив значок.


@Composable
fun SearchBar(
    modifier: Modifier = Modifier
) {
    TextField(
        value = "",
        onValueChange = {},
        leadingIcon = {
            Icon(
                imageVector = Icons.Default.Search,
                contentDescription = null
            )
        },
        colors = TextFieldDefaults.colors(
            unfocusedContainerColor = MaterialTheme.colorScheme.surface,
            focusedContainerColor = MaterialTheme.colorScheme.surface
        ),
        placeholder = {
            Text(stringResource(R.string.placeholder_search))
        },
        modifier = modifier
            .fillMaxWidth()
            .heightIn(min = 56.dp)
    )
}

maxLines/minLines

Число строк в текстовом поле можно установить через параметр maxLines.

В версии Compose 1.4 у компонентов TextField, BasicTextField, OutlinedTextField появился новый параметр minLines.

isError

Чтобы привлечь внимание пользователя к неправильным символам в текстовом поле, можно использовать специальный параметр isError и перевести поле в "ошибочное" состояние. В этом случае нижняя полоска меняет свой цвет.


@Composable
fun Content(modifier: Modifier = Modifier) {
    Column(
        modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(80.dp)
    ) {
        var text by remember { mutableStateOf("") }
        var errorState by remember { mutableStateOf(false) }
        var errorMessage by remember { mutableStateOf("") }

        TextField(
            value = text,
            onValueChange = {
                text = it
                when {
                    text.isEmpty() -> {
                        errorState = true
                        errorMessage = "Поле не может быть пустым"
                    }

                    text.startsWith("0") -> {
                        errorState = true
                        errorMessage = "Имя не может начинаться с 0"
                    }

                    else -> {
                        errorState = false
                        errorMessage = ""
                    }
                }
            },
            modifier = modifier.padding(4.dp),
            label = {
                Text(
                    text = if (errorState) errorMessage
                    else "Введите имя кота"
                )
            },
            placeholder = { Text(text = "Барсик") },
            isError = errorState
        )
    }
}

TextField Error

Упрощённый вариант - нужно ввести имя, которое состоит из не менее трёх символов, но не больше девяти. При недопустимых вариантах полоска будет менять свой цвет на красный.


{
    var textState by remember { mutableStateOf(TextFieldValue()) }
    var errorState by remember { mutableStateOf(false) }

    TextField(
        value = textState,
        onValueChange = {
            textState = it
            errorState = it.text.length < 3 || it.text.length > 9
        },
        label = {
            Text(text = "Введите имя кота")
        },
        placeholder = { Text(text = "Барсик") },
        isError = errorState,
    )
}

keyboardOptions/keyboardActions

Клавиатура может иметь специальные значки для разных случаев, например, значок поиска и значок завершения действия "Done".

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


@Composable
fun Content(modifier: Modifier = Modifier) {
    Column(
        modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(80.dp)
    ) {
        var text by remember { mutableStateOf(TextFieldValue()) }
        val focusManager = LocalFocusManager.current

        TextField(
            value = text,
            onValueChange = {
                text = it
            },
            modifier = modifier.padding(4.dp),
            label = {
                Text(text = "Введите имя кота")
            },
            placeholder = { Text(text = "Барсик") },
            keyboardOptions = KeyboardOptions(
                imeAction = ImeAction.Done
            ),
            keyboardActions = KeyboardActions(
                onDone = {
                    focusManager.clearFocus()
                    println(text)
                }
            )
        )
    }
}

Также доступны другие варианты. Заменим на Go (по аналогии попробуйте Send, Search):


keyboardOptions = KeyboardOptions(
    imeAction = ImeAction.Go
),
keyboardActions = KeyboardActions(
    onGo = {
        focusManager.clearFocus()
        println(textState.text)
    }
)

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

Реклама