Приветствую! В этой статье мы создадим снэкбар с обратным отсчетом времени в Jetpack Compose. Эта функция идеально подходит для того, чтобы дать пользователям время обдумать важные действия, например удаление аккаунта.
Оставайтесь с нами, и давайте погрузимся в работу.
Создание снэкбара с обратным отсчетом
Для начала определим composable-функцию SnackbarCountdown
, которая визуально представляет таймер обратного отсчета.
@Composable
private fun SnackbarCountdown(
timerProgress: Float,
secondsRemaining: Int,
color: Color
) {
Box(
modifier = Modifier.size(24.dp),
contentAlignment = Alignment.Center
) {
Canvas(Modifier.matchParentSize()) {
// Определение обводки
val strokeStyle = Stroke(
width = 3.dp.toPx(),
cap = StrokeCap.Round
)
// Рисовка трека
drawCircle(
color = color.copy(alpha = 0.12f),
style = strokeStyle
)
// Рисовка прогресса
drawArc(
color = color,
startAngle = -90f,
sweepAngle = (-360f * timerProgress),
useCenter = false,
style = strokeStyle
)
}
// Отображение оставшихся секунд
Text(
text = secondsRemaining.toString(),
style = LocalTextStyle.current.copy(
fontSize = 14.sp,
color = color
)
)
}
}
Настройка функции CountdownSnackbar
Теперь, когда у нас есть composable-функция SnackbarCountdown
, мы можем определить composable-функцию CountdownSnackbar
, которая принимает несколько параметров для настройки внешнего вида и поведения.
@Composable
fun CountdownSnackbar(
snackbarData: SnackbarData,
modifier: Modifier = Modifier,
durationInSeconds: Int = 5,
actionOnNewLine: Boolean = false,
shape: Shape = SnackbarDefaults.shape,
containerColor: Color = SnackbarDefaults.color,
contentColor: Color = SnackbarDefaults.contentColor,
actionColor: Color = SnackbarDefaults.actionColor,
actionContentColor: Color = SnackbarDefaults.actionContentColor,
dismissActionContentColor: Color = SnackbarDefaults.dismissActionContentColor,
) {
// Здесь - реализация...
}
- snackbarData ➜ данные для снэкбара;
- modifier ➜ модификатор, который будет применен к снэкбару;
- durationInSeconds ➜ продолжительность таймера обратного отсчета;
- actionOnNewLine ➜ опция отображения действия в отдельной строке;
- shape ➜ форма контейнера снэкбара;
- containerColor, contentColor, actionColor, actionContentColor, dismissActionContentColor ➜ различные параметры цветовой стилизации.
Реализация CountdownSnackbar
Управление длительностью и состоянием снэкбара
Далее вычисляем общую продолжительность в миллисекундах и управляем оставшимся временем с помощью переменной состояния. Также используем эффект LaunchedEffect
для обработки обратного отсчета времени и завершения работы снэкбара по истечении времени.
val totalDuration = remember(durationInSeconds) { durationInSeconds * 1000 }
var millisRemaining by remember { mutableIntStateOf(totalDuration) }
LaunchedEffect(snackbarData) {
while (millisRemaining > 0) {
delay(40)
millisRemaining -= 40
}
snackbarData.dismiss()
}
Использование интервала в 40 миллисекунд приводит к обновлению прогресса со скоростью 25 кадров в секунду, что достаточно плавно для человеческого глаза. Вы можете настроить этот интервал под свои нужды.
Работа с кнопками action и dismiss
Для создания кнопок action
и dismiss
мы используем информацию, предоставленную snackbarData
.
// Определите кнопку action, если указана метка actionLabel
val actionLabel = snackbarData.visuals.actionLabel
val actionComposable: (@Composable () -> Unit)? = if (actionLabel != null) {
@Composable {
TextButton(
colors = ButtonDefaults.textButtonColors(contentColor = actionColor),
onClick = { snackbarData.performAction() },
content = { Text(actionLabel) }
)
}
} else {
null
}
// Определите кнопку dismiss, если снэкбар включает действие выключения
val dismissActionComposable: (@Composable () -> Unit)? = if (snackbarData.visuals.withDismissAction) {
@Composable {
IconButton(
onClick = { snackbarData.dismiss() },
content = {
Icon(Icons.Rounded.Close, null)
}
)
}
} else {
null
}
Отображение снэкбара
Наконец, соберем все вместе и выведем на экран снэкбар.
Snackbar(
modifier = modifier.padding(12.dp), // Примените отступ вокруг снэкбара
action = actionComposable,
actionOnNewLine = actionOnNewLine,
dismissAction = dismissActionComposable,
dismissActionContentColor = dismissActionContentColor,
actionContentColor = actionContentColor,
containerColor = containerColor,
contentColor = contentColor,
shape = shape,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
SnackbarCountdown(
// Рассчитайте ход (прогресс) таймера
timerProgress = millisRemaining.toFloat() / totalDuration.toFloat(),
// Рассчитайте оставшиеся секунды
secondsRemaining = (millisRemaining / 1000) + 1,
color = contentColor
)
// Отобразите сообщение
Text(snackbarData.visuals.message)
}
}
Поздравляю! Мы успешно создали снэкбар. Полный код реализации вы найдете на GitHub Gist. Теперь посмотрим, как мы можем использовать снэкбар.
Практический пример
Рассмотрим практический пример. Представим, что пользователь хочет удалить аккаунт и у него есть 5 секунд, чтобы отменить это важное действие.
Box(Modifier.fillMaxSize()) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
// Определите SnackbarHostState для управления состоянием снэкбара
val snackbarHostState = remember { SnackbarHostState() }
Button(
modifier = Modifier.align(Alignment.Center),
onClick = {
scope.launch {
// Показать снэкбар
val result = snackbarHostState.showSnackbar(
message = "User account deleted.",
actionLabel = "UNDO",
duration = SnackbarDuration.Indefinite
)
// Обработка результата снэкбара
when (result) {
SnackbarResult.Dismissed -> {
Toast.makeText(context, "Deleted permanently", Toast.LENGTH_SHORT).show()
}
SnackbarResult.ActionPerformed -> {
Toast.makeText(context, "Deletion canceled", Toast.LENGTH_SHORT).show()
}
}
}
}
) {
Text("Delete Account")
}
// Создайте SnackbarHost для отображения снэкбара
SnackbarHost(
hostState = snackbarHostState,
modifier = Modifier.align(BottomCenter)
) { data ->
// Используйте CountdownSnackbar
CountdownSnackbar(data)
}
}
Вывод:
Читайте также:
- Ознакомление с Work Manager в Android
- Освоение широковещательных приемников в Android
- Улучшение воспроизведения видео с помощью ExoPlayer
Читайте нас в Telegram, VK и Дзен
Перевод статьи Kappdev: How to Create a Countdown Snackbar in Android with Jetpack Compose