更新:最初的问题,然后是更新的示例代码,根据请求触发它。
我在一张懒散的单子里列出了半个小时的时间。
12:00,12:30
该列表附加在伴奏寻呼机库的水平寻呼机上。
当用户在页面之间滑动时,我需要更新所选的时间,如果不靠近顶部/底部,我希望选择的时间始终位于屏幕的中心。
我想出了如何用提供给我们的方法精确地完成这个任务的唯一方法是如下所示。
注意:我之前已经捕获了按钮/列表高度。
val listState = rememberLazyListState()
LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
if (page != selectedPage) {
listState.scrollToItem(0) //Need to be at the top for calc below to work
listState.scrollBy(buttonHeight.toFloat() * page - (listVisibleHeight / 2) + buttonHeight)
}
}
}
这件事做得很好。当我从00:00开始并向下移动列表时,直到我到达中间,并且一旦我到达中间,所选的时间就会随着时间的滚动而停留在中间,并且一直在中间,直到我接近列表的末尾,它开始向下移动。
现在还有一种方法listState.animateScrollBy(float, animation)
很理想,如果你点击了一些不是在中间的东西,它必须把它放回中间,但是当我使用这个方法的时候,绝对不会发生什么事情?
listState.animateScrollBy(buttonHeight.toFloat() * page - (listVisibleHeight / 2) + buttonHeight)
对我来说就像被打破了一样?好像我从来没有调用过这个函数。0滚动,即使当我尝试添加一个非默认动画。我在这里做错什么了吗?
它是在编写1.2.0-字母04和1.2.0-字母06时这样做的。
我可以继续使用scrollBy,但是没有动画,如果用户点击一个时间而不是滑动到一个时间,它会有点不稳定。
现在我知道为什么它是按要求发生的
寻呼机的特殊进口产品
implementation "com.google.accompanist:accompanist-pager:0.24.5-alpha"
implementation "com.google.accompanist:accompanist-pager-indicators:0.24.5-alpha"
注意:寻呼机本身一直不稳定,因为我更新了它,以修复一个较早版本的崩溃.它不太正确,它有时会被卡住。不过,我还没有对此进行调查。
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.animateScrollBy
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.PagerState
@ExperimentalPagerApi
@Composable
fun TestScreen() {
val numberOfRows = 48
val listState = rememberLazyListState()
var selectedRow by remember { mutableStateOf(0) }
var buttonHeight by remember { mutableStateOf(0) }
var listVisibleHeight by remember { mutableStateOf(0) }
val pagerState = PagerState(currentPage = selectedRow)
Row(
modifier = Modifier
.onGloballyPositioned {
listVisibleHeight = it.size.height
}
) {
LazyColumn(
state = listState,
modifier = Modifier
.wrapContentSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
items(numberOfRows) { index ->
Button(
modifier = Modifier
.wrapContentWidth()
.onGloballyPositioned {
buttonHeight = it.size.height
},
onClick = {}
) {
if (index == selectedRow) {
Text(text = index.toString(), color = Color.White)
} else {
Text(text = index.toString(), color = Color.Red)
}
}
}
}
LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
if (page != selectedRow) {
//This doesn't work if selectedRow = page happens before the other code due to recomposition
//If it's after, it executes but it doesn't look right as it moves then highlights
selectedRow = page
listState.scrollToItem(0)
try {
listState.animateScrollBy(distanceToMiddleOfScreen(buttonHeight, listVisibleHeight, page))
} catch (exception: Exception) {
Log.e("scrollBug", "animateScrollBy Exception", exception)
}
}
}
}
HorizontalPager(
count = 48,
state = pagerState,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.background(Color.White),
) { page ->
Text(text = page.toString())
}
}
}
private fun distanceToMiddleOfScreen(itemHeight: Int, totalListHeight: Int, offset: Int): Float {
return itemHeight.toFloat() * offset - (totalListHeight / 2) + itemHeight
}
发布于 2022-04-05 07:00:35
您的寻呼机的行为很奇怪,因为您在reach重组时创建了它的状态:
val pagerState = PagerState(currentPage = selectedRow)
这个初始化器使您可以在您自己的状态中使用,您负责在重新组合之间记住这一点。
在视图中使用它时,若要在重新组合之间保存其状态,需要使用“记住版本”:
val pagerState = rememberPagerState()
在此之后,您的LaunchedEffect
将不会重新启动,也不会停止您的animateScrollBy
。
在关闭这个特征请求之前,我想不出滚动问题的通用解决方案。但是,如果所有项都大小相等,则可以计算当前滚动位置、最终滚动位置,因此可以计算要滚动的差值:
LaunchedEffect(Unit) {
snapshotFlow { pagerState.currentPage }.collect { page ->
if (page != selectedRow) {
selectedRow = page
val currentOffset = listState.firstVisibleItemIndex * buttonHeight + listState.firstVisibleItemScrollOffset
val finalOffset = distanceToMiddleOfScreen(buttonHeight, listVisibleHeight, page)
listState.animateScrollBy(finalOffset - currentOffset)
}
}
}
另外,您的distanceToMiddleOfScreen
也不准确,可以这样修正:
return itemHeight * (offset + 0.5f) - totalListHeight / 2
结果:
https://stackoverflow.com/questions/71743490
复制相似问题