How can I scroll in both directions in Jetpack Compose
C

3

11

I've created a fairly classic collapsing image layout in Jetpack compose, where I have an image at the top of the screen which parallax scrolls away and at a certain point I change the toolbar background from transparent to primarySurface. This is all working quite nicely.

I now want to have a pager of images at the top instead of a single one but the vertical scroll is consuming all the touches in the top part of the screen. I've tried adding a NestedScrollConnection but I still only seem to get the preScroll delta on one axis. I apparently can't even add icons within this area to do a manual pager scroll without the click being consumed. As soon as I remove the verticalScroll from my Column I'm able to get the horizontal scroll events for the pager.

I'm using Compose 1.0.2 and Accompanist 0.18 pager and inset libraries.

This is a gist of the existing code that I want to add a pager into. How can I get both the pager and the vertical scroll to work?

val scrollState = rememberScrollState()
Box {
    val imageHeight =
        if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE) 180.dp else 300.dp
    Box {
        // I want to insert a horizontal pager here
        HeaderImage(
            scrollPosition = scrollState.value,
            info = item.heroImages.first(),
            imageHeight = imageHeight
        )
    }
    val appBarHeight = with(LocalDensity.current) { 56.dp.toPx() }
    val scrollHeight = with(LocalDensity.current) { imageHeight.toPx() - appBarHeight }

    Column(
        Modifier
            .verticalScroll(scrollState)
            .padding(top = imageHeight)
            .fillMaxSize()
    ) { ... }
    TopAppBar( ... )

Here is a github repository where I've tried to show a simple example of the issue. I either end up with a horizontal pager that can't be scrolled vertically or where the main scroll layout also consumes the horizontal scrolls that the pager requires in order to work.

https://github.com/barry-irvine/scroll_issue

Cerys answered 28/9, 2021 at 11:16 Comment(5)
This is still a problem with Compose 1.2.0-beta01 and Accompanist 0.24.8-betaCerys
I didn't get it, should the pager view scroll horizontally in sync with verticalScroll scrolling vertically? or should it be part of vertical scroll?Superdominant
At the moment the vertical scroll consumes all the scroll events (including horizontal) so there is nothing for the pager to get. It just never receives the horizontal scrolls.Cerys
Hi Pylyp, I've created a simple example so that you can hopefully understand the issue. github.com/barry-irvine/scroll_issueCerys
What's wrong with doing it like this? As for me, it works fine - you can scroll both left/right and up/down - the direction is selected at the first drag, which I think is convenient.Superdominant
S
3

There is no problem with placing a horizontal scroll view inside a vertical one: scrolling will work without problems, and the current scrolling direction of the gesture will be chosen based on the first dragged pixels direction.

Column(
    Modifier
        .verticalScroll(scrollState)
) {
    HorizontalPager(/*...*/)
    OtherScrollableContent(/*...*/)
}
Superdominant answered 20/5, 2022 at 9:23 Comment(2)
I had a feeling OP wanted to activate the horizontally scrolling element simultaneously with the vertically scrolling element. As far as I know, this is not possible without basically re-implementing the Compose scrolling mechanism (issue)Cythiacyto
Please upvote the google issue mentioned above to get real diagonal scroll.Caylacaylor
P
3

Modifying the previous answer, it's possible to scroll in both ways (but not possible to do diagonal scrolling):

val scrollStateHorizontal = rememberScrollState()
val scrollStateVertical = rememberScrollState()

Box(
    modifier = Modifier
        .horizontalScroll(scrollStateHorizontal)
        .verticalScroll(scrollStateVertical)
) {
//Content here
}
Pertinacious answered 6/9, 2022 at 7:18 Comment(1)
Note that you don't need to use a Box, a Column also works fine.Barony
S
3

I just created a library to do this. You can scroll in both direction simultaneously with this library. However, it currently lacks a bounce effect and some other features found in the official scrolling modifier.

A simple example:

val scrollState = rememberFreeScrollState()
Column(
    modifier = Modifier
        .fillMaxSize()
        .freeScroll(state = freeScrollState)
) {
    // Content ...
}
Surveying answered 8/2, 2023 at 8:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.