Android
February 24

Скрытие пароля в Android (Jetpack Compose)

Дайте пользователям возможность показать или скрыть пароль.

Реализовать это в Jetpack Compose можно при помощи trailingIcon. Это иконка в конце поля ввода, которую можно сделать кликабельной.

Объявим переменную passwordVisible. Она будет принимать значения true или false в зависимости от того, хочет ли пользователь видеть пароль.

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

Инициализируем passwordVisible через mutableStateOf() , используя делегат by. Пусть изначально пароль будет скрыт — в mutableStateOf() в качестве параметра передаём значение false.

var passwordVisible by rememberSaveable { mutableStateOf(false) }

Для работы с делегатом by импортируем следующие функции:

import androidx.compose.runtime.setValue
import androidx.compose.runtime.getValue

Создадим поле ввода. В OutlinedTextField за отображение текста отвечает параметр visualTransformation.

В коде ниже если passwordVisible == true, то применяется VisualTransformation.None (пароль виден), если false — применяется PasswordVisualTransformation (пароль в виде точек •••••••).

visualTransformation = if (passwordVisible) VisualTransformation.None
else PasswordVisualTransformation()

В ресурсы проекта добавим два значка (ic_visibility_off и ic_visibility_on) для иконки. Передадим в trailingIcon лямбда-выражение:

trailingIcon = {
    IconButton(
        onClick = { passwordVisible = !passwordVisible }
    ) {}
}

IconButton содержит обработчик события:

onClick = { passwordVisible = !passwordVisible }

При нажатии состояние passwordVisible будет инвертироваться.

Ресурс для Icon выбирается динамически в зависимости от значения в переменной passwordVisible.

@Composable
fun PasswordField(
    value: String,
    onValueChange: (String) -> Unit
) {
    var passwordVisible by rememberSaveable { mutableStateOf(false) }

    OutlinedTextField(
        value = value,
        onValueChange = onValueChange,
        label = { Text("Password") },

        visualTransformation = if (passwordVisible) 
        VisualTransformation.None
        else PasswordVisualTransformation(),

        trailingIcon = {
            IconButton(
                onClick = { passwordVisible = !passwordVisible }
            ) {
                Icon(
                    painter = painterResource(
                        if (passwordVisible) R.drawable.ic_visibility_on
                        else R.drawable.ic_visibility_off
                    ),
                    contentDescription = if (passwordVisible) 
                    "Hide password" else "Show password"
                )
            }
        }
    )
}