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

Компонент обновления позволяет пользователям перетаскивать вниз начало содержимого приложения, чтобы обновить данные.

поверхность 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.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
                        }
                )
            }
        }
    }
}

Ключевые моменты о коде

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

Результат

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

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

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