标签页与分页 (Tabs & Pager)
标签页用于在不同内容组之间进行切换。通常与 Pager(类似 ViewPager2)结合使用以实现滑动切换。
1. 基础标签页 (TabRow)
适用于 Tab 数量较少且固定的情况。
kotlin
var state by remember { mutableIntStateOf(0) }
val titles = listOf("推荐", "热门", "关注")
Column {
TabRow(selectedTabIndex = state) {
titles.forEachIndexed { index, title ->
Tab(
selected = state == index,
onClick = { state = index },
text = { Text(title) }
)
}
}
// 内容区域
Text(
modifier = Modifier.align(Alignment.CenterHorizontally).padding(16.dp),
text = "当前页面: ${titles[state]}"
)
}2. 可滚动标签页 (ScrollableTabRow)
当 Tab 数量很多,或者 Tab 宽度不固定时使用。
kotlin
ScrollableTabRow(
selectedTabIndex = state,
edgePadding = 16.dp //起始位置的偏移量
) {
titles.forEachIndexed { index, title ->
Tab(
selected = state == index,
onClick = { state = index },
text = { Text(title) }
)
}
}3. Pager 与 Tabs 联动
这是最常见的场景。我们需要:
- 点击 Tab -> Pager 滚动到对应页。
- 滑动 Pager -> Tab 更新选中状态并滚动指示器。
依赖
HorizontalPager 现已移入 androidx.compose.foundation (Compose 1.4+),不再需要 Accompanist。
kotlin
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TabPagerExample() {
val titles = listOf("首页", "视频", "游戏", "体育", "财经")
// 1. 创建 Pager 状态
val pagerState = rememberPagerState(pageCount = { titles.size })
val scope = rememberCoroutineScope()
Column {
// 2. 绑定 TabRow
ScrollableTabRow(
selectedTabIndex = pagerState.currentPage,
edgePadding = 0.dp,
indicator = { tabPositions ->
// 自定义指示器逻辑,使其跟随 Pager 偏移量平滑移动
// 注意:这里需要配合 pagerState.currentPageOffsetFraction 使用
// 为简化演示,这里使用默认的 TabRowDefaults.Indicator
// 但要指定 modifier 为 tabPositions[pagerState.currentPage]
TabRowDefaults.Indicator(
Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage])
)
}
) {
titles.forEachIndexed { index, title ->
Tab(
selected = pagerState.currentPage == index,
onClick = {
// 3. 点击 Tab 滚动 Pager
scope.launch {
pagerState.animateScrollToPage(index)
}
},
text = { Text(title) }
)
}
}
// 4. Pager 内容
HorizontalPager(state = pagerState) { page ->
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Page $page: ${titles[page]}")
}
}
}
}