Indicadores de progresso

Os indicadores de progresso mostram visualmente o status de uma operação. Eles usam o movimento para chamar a atenção do usuário para o quão perto da conclusão o processo está, como carregar ou processar dados. Eles também podem indicar que o processamento está ocorrendo, sem referência a quão perto da conclusão ele pode estar.

Considere estes três casos de uso em que você pode usar um indicador de progresso:

  • Carregamento de conteúdo: ao buscar conteúdo de uma rede, como carregar uma imagem ou dados para um perfil de usuário.
  • Upload de arquivos: informe ao usuário quanto tempo o upload pode levar.
  • Processamento longo: enquanto um app estiver processando uma grande quantidade de dados, informe ao usuário quanto do total foi concluído.

No Material Design, há dois tipos de indicadores de progresso:

  • Determinado: mostra exatamente quanto progresso foi feito.
  • Indeterminado: anima continuamente, sem considerar o progresso.

Da mesma forma, um indicador de progresso pode assumir uma das duas formas a seguir:

  • Linear: uma barra horizontal que é preenchida da esquerda para a direita.
  • Circular: um círculo cujo traço aumenta de comprimento até abranger toda a circunferência.
Um indicador de progresso linear ao lado de um indicador de progresso circular.
Figura 1. Os dois tipos de indicadores de progresso.

Superfície da API

Embora existam vários elementos que podem ser usados para criar indicadores de progresso consistentes com o Material Design, os parâmetros deles não são muito diferentes. Entre os principais parâmetros que você precisa considerar estão os seguintes:

  • progress: o progresso atual que o indicador mostra. Transmita um Float entre 0.0 e 1.0.
  • color: a cor do indicador. Ou seja, a parte do componente que reflete o progresso e que o abrange totalmente quando o progresso é concluído.
  • trackColor: a cor da faixa em que o indicador é desenhado.

Indicadores determinados

Um indicador determinado reflete exatamente o nível de conclusão de uma ação. Use os combináveis LinearProgressIndicator ou CircularProgressIndicator e transmita um valor para o parâmetro progress.

O snippet a seguir mostra um exemplo relativamente detalhado. Quando o usuário pressiona o botão, o app mostra o indicador de progresso e inicia uma corrotina que aumenta gradualmente o valor de progress. Isso faz com que o indicador de progresso seja iterado.

@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)
    }
}

Quando o carregamento está parcialmente concluído, o indicador linear no exemplo anterior aparece da seguinte forma:

Da mesma forma, o indicador circular aparece assim:

Indicadores indeterminados

Um indicador indeterminado não reflete o quão perto de ser concluída uma operação está. Em vez disso, ele usa o movimento para indicar ao usuário que o processamento está em andamento, mas sem especificar o grau de conclusão.

Para criar um indicador de progresso indeterminado, use o elemento combinável LinearProgressIndicator ou CircularProgressIndicator, mas não transmita um valor para progress. O exemplo a seguir demonstra como alternar um indicador indeterminado pressionando um botão.

@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,
    )
}

Confira um exemplo dessa implementação quando o indicador está ativo:

Confira um exemplo da mesma implementação, mas com LinearProgressIndicator em vez de CircularProgressIndicator.

Outros recursos