Wskaźniki postępu

Wskaźniki postępu wizualnie pokazują stan operacji. Wykorzystują ruch, aby zwrócić uwagę użytkownika na to, jak blisko ukończenia jest proces, np. ładowanie lub przetwarzanie danych. Mogą też oznaczać, że przetwarzanie jest w toku, bez podawania informacji o tym, jak blisko jest zakończenia.

Oto 3 przykłady użycia wskaźnika postępu:

  • Wczytywanie treści: podczas pobierania treści z sieci, np. wczytywania obrazu lub danych profilu użytkownika.
  • Przesyłanie pliku: informuj użytkownika, ile czasu może zająć przesyłanie.
  • Długie przetwarzanie: gdy aplikacja przetwarza dużą ilość danych, informuj użytkownika, ile procent całości zostało już przetworzone.

W Material Design są 2 rodzaje wskaźników postępu:

  • Określony: wyświetla dokładny postęp.
  • Nieokreślony: animacja jest ciągła i niezależna od postępu.

Wskaźnik postępu może przyjmować jedną z tych 2 form:

  • Liniowy: poziomy pasek, który wypełnia się od lewej do prawej.
  • Okrąg: okrąg, którego kreska wydłuża się, aż obejmie cały obwód.
Liniowy wskaźnik postępu obok kołowego wskaźnika postępu.
Rysunek 1. 2 rodzaje wskaźników postępu.

API Surface

Chociaż do tworzenia wskaźników postępu zgodnych z Material Design możesz używać kilku funkcji kompozycyjnych, ich parametry nie różnią się zbytnio. Oto najważniejsze parametry, o których warto pamiętać:

  • progress: bieżący postęp wyświetlany przez wskaźnik. Przekaż wartość Float z zakresu od 0.0 do 1.0.
  • color: kolor rzeczywistego wskaźnika. Jest to część komponentu, która odzwierciedla postęp i w pełni obejmuje komponent po zakończeniu postępu.
  • trackColor: kolor ścieżki, nad którą jest rysowany wskaźnik.

Wskaźniki deterministyczne

Wskaźnik określony dokładnie odzwierciedla stopień ukończenia działania. Użyj funkcji kompozycyjnych LinearProgressIndicator lub CircularProgressIndicator i przekaż wartość parametru progress.

Poniższy fragment zawiera dość szczegółowy przykład. Gdy użytkownik naciśnie przycisk, aplikacja wyświetli wskaźnik postępu i uruchomi korutynę, która stopniowo zwiększa wartość progress. Powoduje to, że wskaźnik postępu zwiększa się po kolei.

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

Gdy ładowanie jest częściowo zakończone, wskaźnik liniowy z poprzedniego przykładu wygląda tak:

Okrągły wskaźnik wygląda tak:

Wskaźniki nieokreślone

Wskaźnik nieokreślony nie odzwierciedla stopnia zaawansowania operacji. Zamiast tego za pomocą ruchu informuje użytkownika, że przetwarzanie jest w toku, ale nie określa stopnia ukończenia.

Aby utworzyć wskaźnik nieokreślonego postępu, użyj funkcji kompozycyjnej LinearProgressIndicator lub CircularProgressIndicator, ale nie przekazuj wartości dla parametru progress. Poniższy przykład pokazuje, jak przełączać wskaźnik nieokreślony za pomocą przycisku.

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

Poniżej znajdziesz przykład tej implementacji, gdy wskaźnik jest aktywny:

Poniżej znajdziesz przykład tej samej implementacji, ale z użyciem znaku LinearProgressIndicator zamiast CircularProgressIndicator.

Dodatkowe materiały