Разрешение конфликта прокрутки: PullToRefresh (вертикальный) и горизонтальный пейджер в Jetpack Compose

Я разрабатываю экран в 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
                }
            }
        }
    }
2
0
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, убедитесь, что вы используете материал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.

Однако с модификатором verticalScrollfillMaxSize больше не работает. Вместо fillMaxSize мы можем использовать модификатор fillParentSize, который устанавливает размер, равный PullToRefreshBox Composable, который предоставляет BoxScope.

Выход:

Спасибо за вашу помощь. Это сработало отлично. Кроме того, как я проверил, я использовал Материал 3 PullToRefresh.

Azin Alizadeh 26.07.2024 11:13

@AzinAlizadeh Я рад слышать, что это сработало для тебя! Извините, я ошибочно подумал, что вы используете вариант материала2, потому что я не увидел PullToRefreshBox в опубликованном вами коде,

BenjyTec 26.07.2024 11:17

На самом деле, я использовал предыдущую функцию в посте, потому что прочитал ваш ответ и попытался использовать PullRefreshBox, но компилятор не распознал эту функцию (возможно, я использую неправильную версию зависимости). Я думал, что это функция, которую вы написали самостоятельно. Я искал и не смог найти в документации составной элемент PullRefreshBox. Однако использованные мной PullToRefreshState и PullToRefreshContainer были из Материала 3.

Azin Alizadeh 26.07.2024 12:05

Я только что обнаружил, что PullToRefreshBox действительно был добавлен всего месяц назад в material3:1.3.0-beta05, поэтому убедитесь, что вы используете последнюю версию зависимости.

BenjyTec 26.07.2024 12:43

Другие вопросы по теме