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

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

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

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

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

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

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

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

API Surface

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

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

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

Детерминированный индикатор точно показывает, насколько завершено действие. Используйте композиции 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.

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