Przeciągnij w dół, aby odświeżyć

Komponent „Przeciągnij, aby odświeżyć” umożliwia użytkownikom przeciągnięcie w dół na początku treści aplikacji w celu odświeżenia danych.

Powierzchnia interfejsu API

Użyj komponentu PullToRefreshBox, aby wdrożyć funkcję „przeciągnij, aby odświeżyć”, która działa jako kontener dla treści z możliwością przewijania. Na zachowanie i wygląd odświeżania wpływają te kluczowe parametry:

  • isRefreshing: wartość logiczna wskazująca, czy odświeżanie jest w toku.
  • onRefresh: funkcja Lambda, która jest wykonywana, gdy użytkownik inicjuje odświeżanie.
  • indicator: dostosowuje wskaźnik rysowany przez system podczas odświeżania przez przeciągnięcie.

Podstawowy przykład

Ten fragment kodu pokazuje podstawowe użycie PullToRefreshBox:

@Composable
fun PullToRefreshBasicSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

Najważniejsze informacje o kodzie

  • Komponent PullToRefreshBox opakowuje komponent LazyColumn, który wyświetla listę ciągów znaków.
  • PullToRefreshBox wymaga parametrów isRefreshingonRefresh.
  • Treści w bloku PullToRefreshBox reprezentują przewijane treści.

Wynik

Ten film pokazuje podstawową implementację funkcji „przeciągnij, aby odświeżyć” z poprzedniego kodu:

Rysunek 1. Podstawowa implementacja funkcji „przeciągnij, aby odświeżyć” na liście elementów.

Przykład zaawansowany: dostosowywanie koloru wskaźnika

@Composable
fun PullToRefreshCustomStyleSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier,
        state = state,
        indicator = {
            Indicator(
                modifier = Modifier.align(Alignment.TopCenter),
                isRefreshing = isRefreshing,
                containerColor = MaterialTheme.colorScheme.primaryContainer,
                color = MaterialTheme.colorScheme.onPrimaryContainer,
                state = state
            )
        },
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

Najważniejsze informacje o kodzie

  • Kolor wskaźnika jest dostosowywany za pomocą właściwości containerColorcolor w parametrze indicator.
  • rememberPullToRefreshState() zarządza stanem działania odświeżania. Używasz tego stanu w połączeniu z parametrem indicator.

Wynik

Ten film pokazuje implementację funkcji „przeciągnij, aby odświeżyć” z kolorowym wskaźnikiem:

Rysunek 2. Implementacja funkcji „przeciągnij, aby odświeżyć” ze stylem niestandardowym.

Przykład zaawansowany: tworzenie w pełni dostosowanego wskaźnika

Możesz tworzyć złożone wskaźniki niestandardowe, korzystając z istniejących komponentów i animacji.Ten fragment kodu pokazuje, jak utworzyć w pełni niestandardowy wskaźnik w implementacji funkcji „przeciągnij, aby odświeżyć”:

@Composable
fun PullToRefreshCustomIndicatorSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier,
        state = state,
        indicator = {
            MyCustomIndicator(
                state = state,
                isRefreshing = isRefreshing,
                modifier = Modifier.align(Alignment.TopCenter)
            )
        }
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

// ...
@Composable
fun MyCustomIndicator(
    state: PullToRefreshState,
    isRefreshing: Boolean,
    modifier: Modifier = Modifier,
) {
    Box(
        modifier = modifier.pullToRefreshIndicator(
            state = state,
            isRefreshing = isRefreshing,
            containerColor = PullToRefreshDefaults.containerColor,
            threshold = PositionalThreshold
        ),
        contentAlignment = Alignment.Center
    ) {
        Crossfade(
            targetState = isRefreshing,
            animationSpec = tween(durationMillis = CROSSFADE_DURATION_MILLIS),
            modifier = Modifier.align(Alignment.Center)
        ) { refreshing ->
            if (refreshing) {
                CircularProgressIndicator(Modifier.size(SPINNER_SIZE))
            } else {
                val distanceFraction = { state.distanceFraction.coerceIn(0f, 1f) }
                Icon(
                    imageVector = Icons.Filled.CloudDownload,
                    contentDescription = "Refresh",
                    modifier = Modifier
                        .size(18.dp)
                        .graphicsLayer {
                            val progress = distanceFraction()
                            this.alpha = progress
                            this.scaleX = progress
                            this.scaleY = progress
                        }
                )
            }
        }
    }
}

Najważniejsze informacje o kodzie

  • Poprzedni fragment kodu korzystał z wartości Indicator dostarczonej przez bibliotekę. Ten fragment kodu tworzy funkcję kompozycyjną niestandardowego wskaźnika o nazwie MyCustomIndicator. W tym komponencie modyfikator pullToRefreshIndicator odpowiada za pozycjonowanie i wywoływanie odświeżania.
  • Podobnie jak w poprzednim fragmencie kodu przykład wyodrębnia instancję PullToRefreshState, dzięki czemu możesz przekazać tę samą instancję do funkcji PullToRefreshBoxpullToRefreshModifier.
  • W przykładzie użyto koloru kontenera i progu pozycji z klasy PullToRefreshDefaults. Dzięki temu możesz ponownie wykorzystać domyślne działanie i styl z biblioteki Material, dostosowując tylko te elementy, które Cię interesują.
  • MyCustomIndicator używa Crossfade do przechodzenia między ikoną chmury a CircularProgressIndicator. Ikona chmury powiększa się, gdy użytkownik przeciąga palcem w dół, a gdy rozpoczyna się odświeżanie, zmienia się w CircularProgressIndicator.
    • targetState używa isRefreshing, aby określić, który stan ma być wyświetlany (ikona chmury lub kołowy wskaźnik postępu).
    • animationSpec definiuje tween animację przejścia o określonym czasie trwania CROSSFADE_DURATION_MILLIS.
    • state.distanceFraction – odległość, o jaką użytkownik przesunął w dół, od 0f (brak przesunięcia) do 1f (pełne przesunięcie).
    • Modyfikator graphicsLayer zmienia skalę i przezroczystość.

Wynik

Ten film przedstawia niestandardowy wskaźnik z poprzedniego kodu:

Rysunek 3. Implementacja funkcji „przeciągnij, aby odświeżyć” z niestandardowym wskaźnikiem.

Dodatkowe materiały