Потяните, чтобы обновить

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

Поверхность API

Используйте компонент PullToRefreshBox для реализации функции обновления страницы по мере необходимости, который будет выступать в качестве контейнера для прокручиваемого контента. Следующие ключевые параметры управляют поведением и внешним видом обновления:

  • isRefreshing : Логическое значение, указывающее, выполняется ли обновление страницы.
  • onRefresh : лямбда-функция, которая выполняется, когда пользователь инициирует обновление страницы.
  • indicator : Настраивает индикатор, который система отображает при обновлении страницы по требованию.

Простой пример

Этот фрагмент кода демонстрирует базовое использование 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) })
            }
        }
    }
}

Основные моменты, касающиеся кода.

  • PullToRefreshBox оборачивает LazyColumn , который отображает список строк.
  • Для PullToRefreshBox требуются параметры isRefreshing и onRefresh .
  • Содержимое блока PullToRefreshBox представляет собой прокручиваемый контент.

Результат

В этом видео демонстрируется базовая реализация функции обновления страницы потянув вниз, представленная в приведенном выше коде:

Рисунок 1. Базовая реализация функции обновления списка элементов по мере необходимости.

Расширенный пример: Настройка цвета индикатора

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

Основные моменты, касающиеся кода.

  • Цвет индикатора настраивается с помощью свойств containerColor и color в параметре indicator .
  • rememberPullToRefreshState() управляет состоянием действия обновления. Это состояние используется совместно с параметром indicator .

Результат

В этом видео показана реализация функции обновления страницы потянув вниз с использованием цветного индикатора:

Рисунок 2. Реализация функции обновления страницы потянув вниз с использованием пользовательского стиля.

Расширенный пример: создание полностью настраиваемого индикатора.

Вы можете создавать сложные пользовательские индикаторы, используя существующие элементы управления и анимации. Этот фрагмент кода демонстрирует, как создать полностью пользовательский индикатор в вашей реализации обновления страницы по мере необходимости:

@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.pullToRefresh(
            state = state,
            isRefreshing = isRefreshing,
            threshold = PositionalThreshold,
            onRefresh = {

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

Основные моменты, касающиеся кода.

  • В предыдущем фрагменте кода использовался Indicator предоставляемый библиотекой. В этом фрагменте создается пользовательский составной индикатор под названием MyCustomIndicator . В этом составном индикаторе модификатор pullToRefreshIndicator отвечает за позиционирование и запуск обновления.
  • Как и в предыдущем фрагменте кода, в примере извлекается экземпляр PullToRefreshState , поэтому вы можете передать один и тот же экземпляр как в PullToRefreshBox так и в pullToRefreshModifier .
  • В примере используются цвет контейнера и пороговое значение положения из класса PullToRefreshDefaults . Таким образом, вы можете повторно использовать поведение и стили по умолчанию из библиотеки Material, настраивая при этом только те элементы, которые вас интересуют.
  • MyCustomIndicator использует Crossfade для перехода между иконкой облака и индикатором CircularProgressIndicator . Иконка облака увеличивается по мере того, как пользователь перемещает курсор, и переходит в индикатор CircularProgressIndicator когда начинается обновление страницы.
    • targetState использует isRefreshing для определения того, какое состояние отображать (значок облака или круговой индикатор выполнения).
    • animationSpec определяет анимацию tween с заданной длительностью CROSSFADE_DURATION_MILLIS .
    • state.distanceFraction показывает, насколько далеко пользователь потянул вниз, от 0f (нет рывка) до 1f (полностью потянут).
    • Модификатор graphicsLayer изменяет масштаб и прозрачность.

Результат

В этом видео показан пользовательский индикатор из приведенного выше кода:

Рисунок 3. Реализация функции обновления страницы потянув вниз с использованием пользовательского индикатора.

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