You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中是否有类似ScrollableTabRow的ScrollableTabColumn?

响应式Tabs布局解决方案(Jetpack Compose)

核心思路就是根据屏幕尺寸自动切换横向/竖向Tabs布局,同时和你当前用的ScrollableTabRow参数完全对齐,让调用方无缝切换,不用改太多代码。

第一步:封装统一的响应式Tab容器

直接写一个ResponsiveTabRow组件,内部根据WindowSizeClass判断屏幕宽度,自动切换手机端的横向滚动Tab和平板端的竖向Tab列:

@Composable
fun ResponsiveTabRow(
    selectedTabIndex: Int,
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    edgePadding: Dp = TabRowDefaults.ScrollableTabRowPadding,
    indicator: @Composable (tabPositions: List<TabPosition>) -> Unit = { tabPositions ->
        TabRowDefaults.Indicator(
            Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex])
        )
    },
    divider: @Composable () -> Unit = {
        TabRowDefaults.Divider()
    },
    tabs: @Composable () -> Unit,
    windowSizeClass: WindowSizeClass
) {
    when (windowSizeClass.widthSizeClass) {
        WidthSizeClass.Compact -> {
            // 手机端:直接用你原来的ScrollableTabRow
            ScrollableTabRow(
                selectedTabIndex = selectedTabIndex,
                modifier = modifier,
                backgroundColor = backgroundColor,
                contentColor = contentColor,
                edgePadding = edgePadding,
                indicator = indicator,
                divider = divider,
                tabs = tabs
            )
        }
        else -> {
            // 平板/大屏:自定义竖向Tab列
            Column(
                modifier = modifier
                    .background(backgroundColor)
                    .padding(vertical = edgePadding)
            ) {
                // 用自定义Layout计算每个Tab的位置,生成竖向的TabPosition
                val tabPositions = remember { mutableStateListOf<TabPosition>() }
                val density = LocalDensity.current

                Layout(
                    content = tabs,
                    modifier = Modifier.weight(1f)
                ) { measurables, constraints ->
                    val placeables = measurables.map { it.measure(constraints.copy(minHeight = 0)) }
                    var yOffset = 0
                    tabPositions.clear()
                    placeables.forEach { placeable ->
                        with(density) {
                            tabPositions.add(
                                TabPosition(
                                    left = 0.dp,
                                    top = yOffset.toDp(),
                                    width = placeable.width.toDp(),
                                    height = placeable.height.toDp()
                                )
                            )
                        }
                        yOffset += placeable.height
                    }
                    layout(constraints.maxWidth, yOffset) {
                        var currentY = 0
                        placeables.forEach { placeable ->
                            placeable.place(0, currentY)
                            currentY += placeable.height
                        }
                    }
                }

                // 指示器和分割线,适配竖向布局
                Column(modifier = Modifier.fillMaxWidth()) {
                    indicator(tabPositions)
                    divider()
                }
            }
        }
    }
}

第二步:调用示例

直接在你的页面中使用这个组件,传入WindowSizeClass即可:

@Composable
fun MainScreen(windowSizeClass: WindowSizeClass) {
    val selectedTab = remember { mutableStateOf(0) }
    val tabTitles = listOf("首页", "分类", "我的", "设置", "收藏")

    ResponsiveTabRow(
        selectedTabIndex = selectedTab.value,
        windowSizeClass = windowSizeClass
    ) {
        tabTitles.forEachIndexed { index, title ->
            Tab(
                selected = selectedTab.value == index,
                onClick = { selectedTab.value = index },
                text = { Text(title) }
            )
        }
    }

    // 对应Tab的内容区域
    when (selectedTab.value) {
        0 -> Text("首页内容")
        1 -> Text("分类内容")
        2 -> Text("我的内容")
        3 -> Text("设置内容")
        4 -> Text("收藏内容")
    }
}

优化:自定义竖向指示器

默认的横向指示器在竖向布局里不太协调,你可以自己写个竖向的指示器替换:

@Composable
fun VerticalTabIndicator(
    modifier: Modifier = Modifier,
    tabPosition: TabPosition,
    color: Color = MaterialTheme.colors.primary,
    width: Dp = 4.dp
) {
    Box(
        modifier = modifier
            .fillMaxHeight()
            .width(width)
            .offset(y = tabPosition.top)
            .background(color)
    )
}

调用时替换indicator参数就行:

ResponsiveTabRow(
    selectedTabIndex = selectedTab.value,
    windowSizeClass = windowSizeClass,
    indicator = { tabPositions ->
        VerticalTabIndicator(
            tabPosition = tabPositions[selectedTab.value]
        )
    }
) {
    // ... Tab内容
}

内容的提问来源于stack exchange,提问作者Victor Cocuz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 13:10:07