android - 使用 Jetpack Compose ScrollableTabRow 时避免初始滚动

标签 android android-jetpack-compose android-tabs

我正在使用 ScrollableTabRow 来显示大约 60 个选项卡。 一开始,指标应该从“中间”开始。 但是,这会导致在绘制可组合项时出现不需要的滚动动画 - 请参阅视频。我做错了什么还是这个组件有问题?

enter image description here

@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 在可组合项内的两个位置使用:

  1. 在默认指标实现中
  2. 作为 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/

相关文章:

android - Jetpack Compose TextField 捕获键盘 Enter-input

android - 以编程方式更改 ActionBar 选项卡下划线颜色

android - UnsatisfiedLinkError : n_Mat while using opencv2. 4.3 与 android 4.0

android - Jetpack compose navigation popUpTo inclusive true 未从 backstack 清除可组合屏幕

Ubuntu 11.04 中的 Android 虚拟设备 (AVD) 问题

android - 为什么 viewModel() 在组合中使用,而 viewModels() 在 Activity 或 fragment 中使用?

android - 在另一个类的 ProgressBar 上设置进度

android - 调用新 Activity 时不显示标签栏

java - 如何给WebView添加后退按钮?

android - 确保应用程序在按下后退按钮时关闭 Android