0

I’m working on a Jetpack Compose app where I want a Text item in a LazyColumn become transparent as it scrolls under a semi-transparent TopAppBar. To achieve this, I’m using onGloballyPositioned to get the Text’s Y-coordinate and trigger an animation when it approaches the TopAppBar.

However, both positionInWindow() and positionInRoot() return the same Y-coordinate, which seems to include the status bar height. As a result, the animation starts too late — when the Text is fully under the TopAppBar instead of when its top edge touches the TopAppBar. My Scaffold uses statusBarsPadding() to handle system insets, but this doesn’t affect the coordinate system.

How to get the coordinates inside Composable window (not from the edge of screen) desirably without crutches like counting the size of statusBar?

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            ExampleTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Demo(Modifier.padding(innerPadding))
                }
            }
        }
    }
}
@Composable
internal fun Demo(modifier: Modifier = Modifier) {
    val density = LocalDensity.current
    val topBarHeightPx = with(density) { 60.dp.toPx() }
    var wineTitleOffset by remember { mutableStateOf(Offset.Zero) }

    val nameFraction = ((topBarHeightPx - wineTitleOffset.y) / topBarHeightPx * 2).coerceIn(0f, 1f)
    val textColor = lerp(0f, 1f, nameFraction)

    Scaffold(
        modifier = modifier,
        contentWindowInsets = WindowInsets.systemBars,
        topBar = {...}
    ) {
        LazyColumn{
            item { Spacer(modifier = Modifier.height(60.dp)) }
            items(10) {
                Text(text = "Hello, Peter")
            }
            item {
                Layout(
                    content = {
                        Text(
                            "EXAMPLE TEXT",
                            fontWeight = FontWeight.Bold,
                            fontSize = 20.sp,
                            modifier = Modifier
                                .layoutId(WineName)
                                .wrapContentHeight(align = Alignment.CenterVertically)
// COUNTING THE COORDINATES:
                                .onGloballyPositioned { coordinates ->
                                    val windowPos = coordinates.positionInWindow()
                                    val rootPos = coordinates.positionInRoot()
                                    Log.d("Position", "Window: $windowPos | Root: $rootPos")
                                 
                                    val pos = coordinates.positionInRoot()
                                    wineTitleOffset = Offset(pos.x, pos.y)
                                }
                            ,
                            textAlign = TextAlign.Center,
                            color = Color.Black.copy(alpha = textColor)
                        )
                    }...

example of output:

Window: Offset(0.0, 196.0) | Root: Offset(0.0, 196.0)

Sorry, I cannot add a picture as I do not have enough reputation

1
  • Honestly, it looks like you are overkilling it, cant you just add top padding to Lazy column? Commented Jul 21 at 11:30

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.