Jetpack Compose animateScrollTo 到绝对坐标或直接到元素
Jetpack Compose animateScrollTo to absolute coordinates or direct to element
为了在撰写中滚动,我使用 scrollState.animateScrollTo() 并通过 onGloballyPositioned {positionInRoot/positionInParent} 获取坐标元素。
animateScrollTo 按偏移值移动。所以如果我们在使用 animateScrollTo 时不在屏幕顶部,那么我们有一个间隙和移动后元素不在屏幕顶部。
我们可以,先滚动到顶部,然后滚动到元素的坐标:
coroutineScope.launch {
scrollState.scrollTo(0)
delay(50)
scrollState.animateScrollTo(sectionTwoCoordinates.roundToInt())
}
但是我不喜欢。
所以也许我们可以获得所有元素的绝对坐标,然后滚动到它们。或者以某种方式将 id 设置为元素并按 ID 滚动。
我也不能在主项目中使用 LazyColumn,所以需要不基于它的解决方案
@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")
}
}
}
}
这里需要根据parent position
得到Coordinates
所以你需要使用:
layoutCoordinates.positionInParent()
而不是
layoutCoordinates.positionInRoot()
示例:
Column(modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned
{ layoutCoordinates ->
sectionThreeCoordinates = ayoutCoordinates.positionInParent().y
}
)
{ /* content */ }
为了在撰写中滚动,我使用 scrollState.animateScrollTo() 并通过 onGloballyPositioned {positionInRoot/positionInParent} 获取坐标元素。
animateScrollTo 按偏移值移动。所以如果我们在使用 animateScrollTo 时不在屏幕顶部,那么我们有一个间隙和移动后元素不在屏幕顶部。
我们可以,先滚动到顶部,然后滚动到元素的坐标:
coroutineScope.launch {
scrollState.scrollTo(0)
delay(50)
scrollState.animateScrollTo(sectionTwoCoordinates.roundToInt())
}
但是我不喜欢。
所以也许我们可以获得所有元素的绝对坐标,然后滚动到它们。或者以某种方式将 id 设置为元素并按 ID 滚动。 我也不能在主项目中使用 LazyColumn,所以需要不基于它的解决方案
@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")
}
}
}
}
这里需要根据parent position
Coordinates
所以你需要使用:
layoutCoordinates.positionInParent()
而不是
layoutCoordinates.positionInRoot()
示例:
Column(modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned
{ layoutCoordinates ->
sectionThreeCoordinates = ayoutCoordinates.positionInParent().y
}
)
{ /* content */ }