(Jetpack Compose) How to calculate parallax correctly?

Issue

I need to do a parallax implementation and in addition when user is scrolling down actionbar should appear. I am following this tutorial:

https://proandroiddev.com/parallax-in-jetpack-compose-bf521244f49

There is an implementation:

@Composable
fun HeaderBarParallaxScroll() {
    val scrollState = rememberScrollState()
    Box {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .verticalScroll(scrollState),
        ) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(500.dp)
                    .background(Color.White)
                    .graphicsLayer {
                        Log.e(
                            "scroll",
                            "${scrollState.value.toFloat()}, max = ${scrollState.maxValue}, ratio = ${(scrollState.value.toFloat() / scrollState.maxValue)}"
                        )
                        alpha = 1f - ((scrollState.value.toFloat() / scrollState.maxValue) * 1.5f)
                        translationY = 0.5f * scrollState.value
                    },
                contentAlignment = Alignment.Center
            ) {
                Image(
                    painterResource(id = R.drawable.ic_launcher_foreground),
                    contentDescription = "tiger parallax",
                    contentScale = ContentScale.Crop,
                    modifier = Modifier.fillMaxSize()
                )
            }

            repeat(100) {
                Text(
                    text = "MyText",
                    modifier = Modifier.background(
                        Color.White
                    ),
                    style = TextStyle(
                        color = Color.Red,
                        fontSize = 24.sp
                    )
                )
            }
        }

        Box(
            modifier = Modifier
                .alpha(min(1f, (scrollState.value.toFloat() / scrollState.maxValue) * 5f))
                .fillMaxWidth()
                .height(60.dp)
                .background(Color.Yellow),
            contentAlignment = Alignment.CenterStart
        ) {
            Text(
                text = "Header bar",
                modifier = Modifier.padding(horizontal = 16.dp),
                style = TextStyle(
                    fontSize = 24.sp,
                    fontWeight = FontWeight.W900,
                    color = Color.Black
                )
            )
        }
    }
}

Looks like everything is working as expected, however, if I change the value repeat in this block

repeat(100) {
                Text(
                    text = "MyText",
                    modifier = Modifier.background(
                        Color.White
                    ),
                    style = TextStyle(
                        color = Color.Red,
                        fontSize = 24.sp
                    )
                )
            }

instead of 100 -> 1000 parallax working slower and in order for the actionbar to appear I need to scroll like half of the list, so to put it differently parallax responsiveness depends on how many items (height) are in the content. Eg: if it is 100 it works as expected, however, if it is 1000 it works much slower…

How to make it work properly?

Solution

Don’t calculate the ratio based on the scroll.maxValue, but use the screen height as the max bound. Get it in pixels like this.

val screenHeight = with (LocalDensity.current) { LocalConfiguration.current.screenHeightDp.dp.roundToPx() }

These are all composables, so you’ll need to call this logic within a Composable scope. After the initialization, of course, the variable can be used anywhere, even in non-composable scopes.

Answered By – Richard Onslow Roper

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published