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
@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")
}
}
}
}