Wskaźniki postępu

Wskaźniki postępu wizualnie pokazują stan operacji. Wykorzystują one ruch, aby zwrócić uwagę użytkownika na czas, w jakim kończy się proces, np. do wczytywania lub przetwarzania danych. Mogą też oznaczać, że przetwarzanie jest w toku, bez względu na to, jak blisko niego może być.

Weź pod uwagę te 3 przypadki, w których możesz użyć wskaźnika postępu:

  • Wczytywanie treści: podczas pobierania treści z sieci, np. wczytywania obrazu lub danych z profilu użytkownika.
  • Przesyłanie pliku: informujesz użytkownika o tym, ile czasu może zająć przesyłanie.
  • Długie przetwarzanie: gdy aplikacja przetwarza dużą ilość danych, pokaż użytkownikowi, jaka część wszystkich danych została już zrealizowana.

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

  • Określ: pokazuje dokładnie dotychczasowy postęp.
  • Nieokreślony: animacja zmienia się w sposób ciągły, bez względu na postęp.

Wskaźnik postępu może też wyświetlać się na dwa sposoby:

  • Liniowy: poziomy pasek, który wypełnia się od lewej do prawej.
  • Okrąg: okrąg, którego pociągnięcie zwiększa się, aż obejmie pełny obwód okręgu.
Liniowy wskaźnik postępu wraz z okrągłym wskaźnikiem postępu.
Rysunek 1. Te 2 rodzaje wskaźników postępu.

Powierzchnia interfejsu API

Chociaż istnieje kilka elementów kompozycyjnych, których można użyć do utworzenia pływających przycisków poleceń zgodnych z interfejsem Material Design, ich parametry nie różnią się znacząco. Oto najważniejsze parametry, o których należy pamiętać:

  • progress: bieżący postęp wyświetlany na wskaźniku. Miń Float między 0.0 a 1.0.
  • color: kolor rzeczywistego wskaźnika. Jest to część komponentu, która odzwierciedla postęp i obejmuje go w całości po jego zakończeniu.
  • trackColor: kolor ścieżki, na której rysowany jest wskaźnik.

Określ wskaźniki

Wskaźnik określający dokładnie odzwierciedla stopień ukończenia działania. Użyj elementów kompozycyjnych LinearProgressIndicator lub CircularProgressIndicator i przekaż wartość parametru progress.

Ten fragment to dość szczegółowy przykład. Gdy użytkownik naciśnie przycisk, aplikacja wyświetli wskaźnik postępu oraz uruchomi współrzędną, która stopniowo zwiększa wartość progress. W rezultacie wskaźnik postępu powtarza się kolejno.

@Composable
fun LinearDeterminateIndicator() {
    var currentProgress by remember { mutableStateOf(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)
    }
}

Jeśli wczytywanie zostało częściowo ukończone, wskaźnik liniowy z poprzedniego przykładu wygląda tak:

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

Nieokreślone wskaźniki

Nieokreślony wskaźnik nie pokazuje, jak blisko zakończenia operacji jest jej wykonanie. Ruch ten wskazuje użytkownikowi, że przetwarzanie trwa, chociaż bez określania jego stopnia zakończenia.

Aby utworzyć nieokreślony wskaźnik postępu, użyj funkcji kompozycyjnej LinearProgressIndicator lub CircularProgressIndicator, ale nie przekazuj wartości progress. Ten przykład pokazuje, jak przełączać wskaźnik nieokreślony jednym naciśnięciem 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,
    )
}

Oto przykład implementacji, gdy wskaźnik jest aktywny:

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

Dodatkowe materiały