我正在使用 ScrollableTabRow
来显示大约 60 个选项卡。
一开始,指标应该从“中间”开始。
但是,这会导致在绘制可组合项时出现不需要的滚动动画 - 请参阅视频。我做错了什么还是这个组件有问题?
@Composable
@Preview
fun MinimalTabExample() {
val tabCount = 60
var selectedTabIndex by remember { mutableStateOf(tabCount / 2) }
ScrollableTabRow(selectedTabIndex = selectedTabIndex) {
repeat(tabCount) { tabNumber ->
Tab(
selected = selectedTabIndex == tabNumber,
onClick = { selectedTabIndex = tabNumber },
text = { Text(text = "Tab #$tabNumber") }
)
}
}
}
但是你为什么要这样做呢? 我正在编写一个类似日历的应用程序,并且有一个每日详细信息 View 。 从那里想要一种快速导航到相邻日期的方法。 future 一个月和过去一个月(相对于所选月份)是我的目标。
最佳答案
不,你没有做错。此外,该组件并不是真正有缺陷,而是您看到的行为是一个实现细节。
如果我们检查 ScrollableTabRow
可组合项的实现,我们会发现 selectedTabIndex
在可组合项内的两个位置使用:
- 在默认指标实现中
- 作为
scrollableTableData.onLaidOut
调用的输入参数
#1 用于在布局内定位选项卡,因此这个问题并不有趣。
#2 用于滚动到选定的选项卡索引。
下面的代码显示了如何设置初始滚动状态,然后调用 scrollableTabData.onLaidOut
val scrollState = rememberScrollState()
val coroutineScope = rememberCoroutineScope()
val scrollableTabData = remember(scrollState, coroutineScope) {
ScrollableTabData(
scrollState = scrollState,
coroutineScope = coroutineScope
)
}
// ...
scrollableTabData.onLaidOut(
density = this@SubcomposeLayout,
edgeOffset = padding,
tabPositions = tabPositions,
selectedTab = selectedTabIndex // <-- selectedTabIndex is passed here
)
这就是上面调用的实现
fun onLaidOut(
density: Density,
edgeOffset: Int,
tabPositions: List<TabPosition>,
selectedTab: Int
) {
// Animate if the new tab is different from the old tab, or this is called for the first
// time (i.e selectedTab is `null`).
if (this.selectedTab != selectedTab) {
this.selectedTab = selectedTab
tabPositions.getOrNull(selectedTab)?.let {
// Scrolls to the tab with [tabPosition], trying to place it in the center of the
// screen or as close to the center as possible.
val calculatedOffset = it.calculateTabOffset(density, edgeOffset, tabPositions)
if (scrollState.value != calculatedOffset) {
coroutineScope.launch {
scrollState.animateScrollTo( // <-- even the initial scroll is done using an animation
calculatedOffset,
animationSpec = ScrollableTabRowScrollSpec
)
}
}
}
}
}
正如我们从第一条评论中已经看到的
Animate if the new tab is different from the old tab, or this is called for the first time
而且在实现中,即使是第一次使用动画设置滚动偏移。
coroutineScope.launch {
scrollState.animateScrollTo(
calculatedOffset,
animationSpec = ScrollableTabRowScrollSpec
)
}
并且 ScrollableTabRow
类没有公开控制此行为的方法。
关于android - 使用 Jetpack Compose ScrollableTabRow 时避免初始滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72769677/