Я разрабатываю экран в Jetpack Compose, который сочетает в себе два компонента прокрутки: PullToRefresh для вертикальной прокрутки и ImageSlider, реализованный с использованием HorizontalPager для горизонтальной прокрутки. PullToRefresh позволит пользователям обновлять содержимое экрана, потянув его вниз. Однако я столкнулся с проблемой, из-за которой жест вертикальной прокрутки для PullToRefresh не обнаруживается. В результате я не могу запустить операцию обновления, потянув экран вниз. Горизонтальная прокрутка в ImageSlider работает должным образом, но, похоже, мешает обнаружению вертикальной прокрутки.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PullToRefreshContent(
isRefreshing: Boolean,
onRefresh: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
val pullToRefreshState = rememberPullToRefreshState()
Box(modifier = modifier.nestedScroll(nestedScrollConnection)) {
content()
// Refresh logic
LaunchedEffect(isRefreshing) {
if (isRefreshing) pullToRefreshState.startRefresh()
else pullToRefreshState.endRefresh()
}
// PullToRefresh UI
PullToRefreshContainer(
state = pullToRefreshState,
modifier = Modifier.align(Alignment.TopCenter)
)
}
}
@Composable
fun ImageSlider(images: List<Media?>) {
val pagerState = rememberPagerState(initialPage = 0) { images.size }
HorizontalPager(state = pagerState) { currentPage ->
val painter = rememberAsyncImagePainter(model = images[currentPage]?.posterPath)
Card {
Image(painter = painter, contentDescription = null)
}
}
}
Чтобы разрешить этот конфликт, я попытался реализовать собственный NestedScrollConnection для определения направления прокрутки, проверяя смещение по оси y события прокрутки. Я предположил, что положительное смещение по оси y будет указывать на прокрутку вниз. Однако это решение не сработало. При мониторинге событий прокрутки я заметил, что значение смещения y постоянно равно либо 0,0, либо -0,0, независимо от фактического направления прокрутки.
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
//Vertical scroll
return if (available.y > 0) {
//Do refresh operation
onRefresh()
pullToRefreshState.nestedScrollConnection.onPreScroll(available, source)
}
//Horizontal scroll
else {
Offset.Zero
}
}
}
}
Во-первых, убедитесь, что вы используете материал3 pulltorefresh вместо материала2 pullrefresh. Также убедитесь, что вы используете как минимум
implementation 'androidx.compose.material3:material3:1.3.0-beta05'
Я обнаружил, что вы можете использовать комбинацию модификаторов verticalScroll и matchParentSize, чтобы получить желаемую функциональность.
Пожалуйста, попробуйте следующий код:
@Composable
fun PullRefresh() {
var isRefreshing by remember { mutableStateOf(false) }
val state = rememberPullToRefreshState()
val coroutineScope = rememberCoroutineScope()
val onRefresh: () -> Unit = {
isRefreshing = true
coroutineScope.launch {
delay(1000)
isRefreshing = false
}
}
Scaffold(
topBar = {
TopAppBar(
title = { Text("Title") },
)
}
) {
PullToRefreshBox(
modifier = Modifier.fillMaxSize().padding(it),
state = state,
isRefreshing = isRefreshing,
onRefresh = onRefresh,
) {
val pagerState = rememberPagerState { 3 }
HorizontalPager(
modifier = Modifier
.verticalScroll(rememberScrollState())
.matchParentSize(),
state = pagerState
) { currentPage ->
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "PAGE $currentPage")
}
}
}
}
}
PullToRefreshBox
Composable нужен вертикально прокручиваемый дочерний элемент Composable. Мы делаем HorizontalPager
вертикально прокручиваемым, применяя модификатор verticalScroll
.
Однако с модификатором verticalScroll
fillMaxSize
больше не работает. Вместо fillMaxSize
мы можем использовать модификатор fillParentSize
, который устанавливает размер, равный PullToRefreshBox
Composable, который предоставляет BoxScope
.
Выход:
@AzinAlizadeh Я рад слышать, что это сработало для тебя! Извините, я ошибочно подумал, что вы используете вариант материала2, потому что я не увидел PullToRefreshBox
в опубликованном вами коде,
На самом деле, я использовал предыдущую функцию в посте, потому что прочитал ваш ответ и попытался использовать PullRefreshBox, но компилятор не распознал эту функцию (возможно, я использую неправильную версию зависимости). Я думал, что это функция, которую вы написали самостоятельно. Я искал и не смог найти в документации составной элемент PullRefreshBox. Однако использованные мной PullToRefreshState и PullToRefreshContainer были из Материала 3.
Я только что обнаружил, что PullToRefreshBox
действительно был добавлен всего месяц назад в material3:1.3.0-beta05
, поэтому убедитесь, что вы используете последнюю версию зависимости.
Спасибо за вашу помощь. Это сработало отлично. Кроме того, как я проверил, я использовал Материал 3 PullToRefresh.