Android Jetpack Compose 中的Tabs(TabLayout)

本文介绍了如何在Android的JetpackCompose中使用Accompanist库的Pager和PagerIndicators组件创建TabLayout。首先,需要添加依赖,然后创建数据类和屏幕Composable。接着,通过TabRow和Tab配合HorizontalPager实现选项卡切换功能。示例代码展示了完整的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android Jetpack Compose 中的Tabs(TabLayout)

添加依赖

我们需要依赖于2个 accompanist组件,你可以从下面链接中获取最新版本https://github.com/google/accompanist/tree/main/pager#pager-composable-for-jetpack-compose

def accompanist_version = "0.28.0"
implementation "com.google.accompanist:accompanist-pager:$accompanist_version" // Pager
implementation "com.google.accompanist:accompanist-pager-indicators:$accompanist_version" // Pager Indicators

准备

在实现Tabs之前,我们将创建data类和Screen类。

data class TabRowItem(
    val title: String,
    val icon: ImageVector,
    val screen: @Composable () -> Unit,
)

这个数据类可以根据要求更改。您可以删除titleicon,但其中至少一个必须保留。

@Composable
fun TabScreen(
    text: String,
) {
    Box(
        modifier = Modifier
            .fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Text(
            text = text,
            style = MaterialTheme.typography.body1,
        )
    }
}

这将用于我们的示例。您可以并应该稍后更改它。
最后,让我们创建选项卡列表。

val tabRowItems = listOf(
    TabRowItem(
        title = "Tab 1",
        screen = { TabScreen(text = "Tab 1") },
        icon = Icons.Rounded.Place,
    ),
    TabRowItem(
        title = "Tab 2",
        screen = { TabScreen(text = "Tab 2") },
        icon = Icons.Rounded.Search,
    ),
    TabRowItem(
        title = "Tab 3",
        screen = { TabScreen(text = "Tab 3") },
        icon = Icons.Rounded.Star,
    )
)

实现

val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()

pagerState将需要记住和保持页面器的状态。

coroutineScope将用于pagerState滚动。

Column(
    modifier = Modifier
        .padding(contentPadding)
) {
    TabRow(
        selectedTabIndex = pagerState.currentPage,
        indicator = { tabPositions ->
            TabRowDefaults.Indicator(
                Modifier.pagerTabIndicatorOffset(pagerState, tabPositions),
                color = MaterialTheme.colors.secondary
            )
        },
    ) {
        // Will be added later
    }
}

我们首先添加TabRow,这将是Tab的容器。

selectedTabIndex是当前选定选项卡的索引。

indicator表示当前选定的选项卡。

Column(
    modifier = Modifier
        .padding(contentPadding)
) {
    TabRow(
        //..
    ) {
        tabRowItems.forEachIndexed { index, item ->
            Tab(
                selected = pagerState.currentPage == index,
                onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
                icon = {
                   Icon(imageVector = item.icon, contentDescription = "")
                },
                text = {
                    Text(
                        text = item.title,
                        maxLines = 2,
                        overflow = TextOverflow.Ellipsis,
                    )
                }
            )
        }
    }

在TabRow里,我们将创建Tab。由于我们已经创建了tabs列表,因此我们将简单地调用tabRowItems.forEachIndex并设置Tabs

选择selected属性,即此选项卡是否被选中。

icontext是可选的。您可以选择其中一个或两者,就像我们的示例一样。

onClick方法中,我们启动coroutineScope并调用animateScrollToPage函数。它简单地将给定页面动画滚动到视图的中心。

Column(
    modifier = Modifier
        .padding(contentPadding)
) {
    TabRow(
        //...
    ) {
        //...
    }
    HorizontalPager(
        count = tabRowItems.size,
        state = pagerState,
    ) {
        tabRowItems[pagerState.currentPage].screen()
    }
}

HorizontalPager是一种水平滚动布局,允许用户在左右两侧之间翻转项目。

最后,我们将添加HorizontalPagercount是页面数量,state是用于控制或观察分页器状态的对象,我们已经在上面创建了它。

HorizontalPager中,我们将获取当前页面并调用Screen,这也是我们在自定义数据类中已经创建的。
tabs
完整代码如下:

val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()

Column(
    modifier = Modifier
        .padding(contentPadding)
) {
    TabRow(
        selectedTabIndex = pagerState.currentPage,
        indicator = { tabPositions ->
            TabRowDefaults.Indicator(
                Modifier.pagerTabIndicatorOffset(pagerState, tabPositions),
                color = MaterialTheme.colors.secondary
            )
        },
    ) {
        tabRowItems.forEachIndexed { index, item ->
            Tab(
                selected = pagerState.currentPage == index,
                onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
                icon = {
                   Icon(imageVector = item.icon, contentDescription = "")
                },
                text = {
                    Text(
                        text = item.title,
                        maxLines = 2,
                        overflow = TextOverflow.Ellipsis,
                    )
                }
            )
        }
    }
    HorizontalPager(
        count = tabRowItems.size,
        state = pagerState,
    ) {
        tabRowItems[pagerState.currentPage].screen()
    }
}

效果动画如下:
tabs swipe effects

源码地址

https://johncodeos.com/how-to-create-tabs-with-jetpack-compose/

### Jetpack Compose 实现 TabRow 底部指示器效果 在 Jetpack Compose 中,`TabRow` 组件用于创建标签栏,并可以自定义其样式来满足特定的设计需求。为了实现 `TabRow` 的底部横线效果,可以通过修改 `indicator` 参数来自定义指示器的外观。 下面是一个具体的例子,展示了如何设置带有颜色、高度和宽度可调的底部横线: ```kotlin import androidx.compose.foundation.background import androidx.compose.material.Tab import androidx.compose.material.TabRow import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp @Composable fun CustomIndicatorTabRow() { var selectedIndex by remember { mutableStateOf(0) } val tabs = listOf("Home", "Profile", "Settings") TabRow( selectedTabIndex = selectedIndex, indicator = { tabPositions -> Box( modifier = Modifier .tabIndicatorOffset(tabPositions[selectedIndex]) .height(4.dp) .background(Color.Red) ) }) { tabs.forEachIndexed { index, title -> Tab( text = { Text(text = title) }, selected = selectedIndex == index, onClick = { selectedIndex = index }) } } } ``` 此代码片段中,通过传递给 `TabRow` 构造函数的一个 lambda 表达式的参数 `indicator` 来指定自定义指示器逻辑[^1]。这里使用了一个简单的红色矩形作为选中的选项卡下的指示条;可以根据实际项目的需求调整该部分代码以改变线条的颜色、厚度或其他特性。 对于更复杂的场景,比如渐变色或圆角处理,则可能需要引入额外的绘制命令或者利用其他图形库的支持来进行更加精细的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvin880828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值