2

For scrolling in compose i use scrollState.animateScrollTo() and get coordinate element by onGloballyPositioned {positionInRoot/positionInParent}.

animateScrollTo moving by the offset value. So if we are not on top of the screen when use animateScrollTo, then we have a gap and element not on the top screen after moving.

we can, first scroll to top, then scroll to coordinates of the element:

coroutineScope.launch {
    scrollState.scrollTo(0)
    delay(50)
    scrollState.animateScrollTo(sectionTwoCoordinates.roundToInt())
}

But I don't like it.

So maybe we can get absolute coordinates for all elements, and scroll to them. Or somehow set the id to element and scroll by ID. Also i cant use LazyColumn in main project, so need solution not based on it

enter image description here

@Composable
fun ScrollSections() {
    val coroutineScope = rememberCoroutineScope()
    val scrollState = rememberScrollState()


    var sectionOneCoordinates by remember { mutableStateOf(0f) }
    var sectionTwoCoordinates by remember { mutableStateOf(0f) }
    var sectionThreeCoordinates by remember { mutableStateOf(0f) }

    var showSectionTwo by remember { mutableStateOf(false) }

    Column(
        Modifier
            .fillMaxWidth()
            .background(Color.White)
            .verticalScroll(scrollState)
    ) {
        Spacer(modifier = Modifier.height(400.dp))
        Row(modifier = Modifier.fillMaxWidth()) {
            Button(
                onClick = {
                    coroutineScope.launch {
                        scrollState.animateScrollTo(
                            sectionOneCoordinates.roundToInt()
                        )
                    }
                },
                modifier = Modifier.weight(0.33f)
            ) {
                Text(text = "1")
            }
            Spacer(modifier = Modifier.width(4.dp))
            Button(
                onClick = {
                    coroutineScope.launch {
//                        scrollState.scrollTo(
//                            0
//                        )
//                        delay(50)
                        scrollState.animateScrollTo(
                            sectionTwoCoordinates.roundToInt()
                        )
                    }
                },
                modifier = Modifier.weight(0.33f)
            ) {
                Text(text = "2")
            }
            Spacer(modifier = Modifier.width(4.dp))
            Button(
                onClick = {
                    coroutineScope.launch {
                        scrollState.animateScrollTo(
                            sectionThreeCoordinates.roundToInt()
                        )
                    }
                },
                modifier = Modifier.weight(0.33f)
            ) {
                Text(text = "3")
            }
        }
        Spacer(modifier = Modifier.height(12.dp))
        Button(onClick = { showSectionTwo = !showSectionTwo }) {
            Text(text = "Show Section 2")
        }
        Spacer(modifier = Modifier.height(50.dp))


        Column(modifier = Modifier
            .fillMaxWidth()
            .onGloballyPositioned { layoutCoordinates ->
                sectionOneCoordinates = layoutCoordinates.positionInRoot().y
            }
        ) {
            Text(text = "Section 1", fontSize = 32.sp)
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
                    .background(test1),
                contentAlignment = Alignment.Center
            ) {
                Text("subsection 1")
            }
            Spacer(modifier = Modifier.height(4.dp))
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
                    .background(test2), contentAlignment = Alignment.Center
            ) {
                Text("subsection 2")
            }
            Spacer(modifier = Modifier.height(4.dp))
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
                    .background(test3), contentAlignment = Alignment.Center
            ) {
                Text("subsection 3")
            }
            Spacer(modifier = Modifier.height(4.dp))
            Button(
                onClick = {
                    coroutineScope.launch {
                        scrollState.animateScrollTo(0)
                    }
                },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(text = "Go UP")
            }
        }
        Spacer(modifier = Modifier.height(24.dp))
        if (showSectionTwo) {
            Column(modifier = Modifier
                .fillMaxWidth()
                .onGloballyPositioned { layoutCoordinates ->
                    sectionTwoCoordinates = layoutCoordinates.positionInRoot().y
                }
            ) {
                Text(text = "Section 2", fontSize = 32.sp)
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(200.dp)
                        .background(test4), contentAlignment = Alignment.Center
                ) {
                    Text("subsection 1")
                }
                Spacer(modifier = Modifier.height(4.dp))
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(200.dp)
                        .background(test5), contentAlignment = Alignment.Center
                ) {
                    Text("subsection 2")
                }
                Spacer(modifier = Modifier.height(4.dp))
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(200.dp)
                        .background(test6), contentAlignment = Alignment.Center
                ) {
                    Text("subsection 3")
                }
                Spacer(modifier = Modifier.height(4.dp))
                Button(
                    onClick = {
                        coroutineScope.launch {
                            scrollState.animateScrollTo(0)
                        }
                    },
                    modifier = Modifier.fillMaxWidth()
                ) {
                    Text(text = "Go UP")
                }
            }
        }
        Spacer(modifier = Modifier.height(24.dp))
        Column(modifier = Modifier
            .fillMaxWidth()
            .onGloballyPositioned { layoutCoordinates ->
                sectionThreeCoordinates = layoutCoordinates.positionInRoot().y
            }
        ) {
            Text(text = "Section 3", fontSize = 32.sp)
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
                    .background(test8),
                contentAlignment = Alignment.Center
            ) {
                Text("subsection 1")
            }
            Spacer(modifier = Modifier.height(4.dp))
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
                    .background(test7),
                contentAlignment = Alignment.Center
            ) {
                Text("subsection 2")
            }
            Spacer(modifier = Modifier.height(4.dp))
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
                    .background(test9),
                contentAlignment = Alignment.Center
            ) {
                Text("subsection 3")
            }
            Spacer(modifier = Modifier.height(4.dp))
            Button(
                onClick = {
                    coroutineScope.launch {
                        scrollState.animateScrollTo(0)
                    }
                },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(text = "Go UP")
            }
        }
    }
}

Boris Sadakov
  • 617
  • 1
  • 7
  • 18

1 Answers1

3

Here you require to get Coordinates based on parent position

So you need to use :

layoutCoordinates.positionInParent()

instead of

layoutCoordinates.positionInRoot()

Example :

Column(modifier = Modifier
     .fillMaxWidth()
     .onGloballyPositioned
     { layoutCoordinates ->
          sectionThreeCoordinates = ayoutCoordinates.positionInParent().y
     }
)
{ /* content */ }
Nikunj
  • 3,937
  • 19
  • 33