Индикаторы прогресса

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

Рассмотрим три варианта использования индикатора выполнения:

  • Загрузка контента. При получении контента из сети, например при загрузке изображения или данных для профиля пользователя.
  • Загрузка файла. Сообщите пользователю, сколько времени может занять загрузка.
  • Длительная обработка. Если приложение обрабатывает большой объем данных, покажите пользователю, какая часть работы уже выполнена.

В Material Design есть два типа индикаторов выполнения:

  • Определенный. Показывает, сколько именно выполнено.
  • Неопределенный. Анимация воспроизводится непрерывно, независимо от прогресса.

Индикатор выполнения может быть двух видов:

  • Линейный. Горизонтальная полоса, которая заполняется слева направо.
  • Круг. Круг, обводка которого увеличивается, пока не охватит всю окружность.
Линейный и круговой индикаторы выполнения.
Рисунок 1. Два типа индикаторов выполнения.

API Surface

Хотя для создания индикаторов прогресса в соответствии с Material Design можно использовать несколько composable-функций, их параметры не сильно различаются. Вот основные параметры, которые следует учитывать:

  • progress – текущий прогресс, который показывает индикатор. Передайте значение Float в диапазоне от 0.0 до 1.0.
  • color – цвет индикатора. То есть часть компонента, которая отражает прогресс и которая полностью охватывает компонент, когда прогресс завершен.
  • trackColor – цвет дорожки, на которой нарисован индикатор.

Определенные индикаторы

Определенный индикатор точно отражает, насколько завершено действие. Используйте composable-функцию LinearProgressIndicator или CircularProgressIndicator и передайте значение для параметра progress.

Ниже приведен подробный пример. Когда пользователь нажимает кнопку, приложение показывает индикатор выполнения и запускает сопрограмму, которая постепенно увеличивает значение progress. Это заставляет индикатор прогресса повторяться по очереди.

@Composable
fun LinearDeterminateIndicator() {
    var currentProgress by remember { mutableFloatStateOf(0f) }
    var loading by remember { mutableStateOf(false) }
    val scope = rememberCoroutineScope() // Create a coroutine scope

    Column(
        verticalArrangement = Arrangement.spacedBy(12.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxWidth()
    ) {
        Button(onClick = {
            loading = true
            scope.launch {
                loadProgress { progress ->
                    currentProgress = progress
                }
                loading = false // Reset loading when the coroutine finishes
            }
        }, enabled = !loading) {
            Text("Start loading")
        }

        if (loading) {
            LinearProgressIndicator(
                progress = { currentProgress },
                modifier = Modifier.fillMaxWidth(),
            )
        }
    }
}

/** Iterate the progress value */
suspend fun loadProgress(updateProgress: (Float) -> Unit) {
    for (i in 1..100) {
        updateProgress(i.toFloat() / 100)
        delay(100)
    }
}

Когда загрузка частично завершена, линейный индикатор в предыдущем примере выглядит следующим образом:

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

Индикаторы неопределенного состояния

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

Чтобы создать неопределенный индикатор выполнения, используйте composable-функцию LinearProgressIndicator или CircularProgressIndicator, но не передавайте значение для progress. В следующем примере показано, как можно переключать неопределенный индикатор нажатием кнопки.

@Composable
fun IndeterminateCircularIndicator() {
    var loading by remember { mutableStateOf(false) }

    Button(onClick = { loading = true }, enabled = !loading) {
        Text("Start loading")
    }

    if (!loading) return

    CircularProgressIndicator(
        modifier = Modifier.width(64.dp),
        color = MaterialTheme.colorScheme.secondary,
        trackColor = MaterialTheme.colorScheme.surfaceVariant,
    )
}

Ниже приведен пример реализации, когда индикатор активен.

Ниже приведен пример той же реализации, но с LinearProgressIndicator вместо CircularProgressIndicator.

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