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

Compose点击底部导航项时修改图标颜色/图标的实现方法

Jetpack Compose Bottom Navigation 项启用/禁用状态切换实现

你已经完成NavHost和底部导航的基础搭建的话,直接基于导航栈状态做判断即可,不需要额外维护独立的选中状态,能完全避免状态和页面不同步的问题。

实现步骤

  • 首先统一定义底部导航项的配置,把选中/未选中态的图标、颜色、路由提前封装,避免写重复逻辑:
sealed class BottomNavRoute(
    val routePath: String,
    val activeIcon: ImageVector,
    val inactiveIcon: ImageVector,
    val tabLabel: String,
    val activeTint: Color = Color(0xFF1677FF),
    val inactiveTint: Color = Color(0xFF8C8C8C)
) {
    object Home : BottomNavRoute(
        routePath = "home",
        activeIcon = Icons.Filled.Home,
        inactiveIcon = Icons.Outlined.Home,
        tabLabel = "首页"
    )

    object Discover : BottomNavRoute(
        routePath = "discover",
        activeIcon = Icons.Filled.Explore,
        inactiveIcon = Icons.Outlined.Explore,
        tabLabel = "发现"
    )

    object Mine : BottomNavRoute(
        routePath = "mine",
        activeIcon = Icons.Filled.Person,
        inactiveIcon = Icons.Outlined.Person,
        tabLabel = "我的"
    )
}
  • 在BottomNavigation容器中,直接从NavController获取当前页面路由作为选中判断依据,不要自己单独维护选中下标:
// 绑定导航栈状态,页面切换时会自动触发重组
val currentBackStackEntry by navController.currentBackStackEntryAsState()
val currentActiveRoute = currentBackStackEntry?.destination?.route

BottomNavigation(
    containerColor = Color.White
) {
    val tabList = listOf(BottomNavRoute.Home, BottomNavRoute.Discover, BottomNavRoute.Mine)
    tabList.forEach { tabItem ->
        val isSelected = currentActiveRoute == tabItem.routePath
        BottomNavigationItem(
            selected = isSelected,
            icon = {
                Icon(
                    // 状态切换时自动替换图标:选中用填充款,未选中用轮廓款
                    imageVector = if (isSelected) tabItem.activeIcon else tabItem.inactiveIcon,
                    contentDescription = tabItem.tabLabel,
                    // 同步切换图标颜色,和状态匹配
                    tint = if (isSelected) tabItem.activeTint else tabItem.inactiveTint
                )
            },
            label = {
                Text(
                    text = tabItem.tabLabel,
                    color = if (isSelected) tabItem.activeTint else tabItem.inactiveTint
                )
            },
            onClick = {
                // 导航逻辑加去重配置,避免重复点击创建多个页面实例
                navController.navigate(tabItem.routePath) {
                    popUpTo(navController.graph.findStartDestination().id) {
                        saveState = true
                    }
                    launchSingleTop = true
                    restoreState = true
                }
            }
        )
    }
}

特殊场景适配

如果你需要实现和导航选中无关的临时禁用效果(比如某个tab点击后临时置灰、不可点击),只需要额外维护一个状态映射表即可:

// 存储每个tab的可用状态,key为路由path,value为是否可用
val tabEnableState = remember { mutableStateMapOf<String, Boolean>().apply {
    // 默认所有tab可用
    BottomNavRoute::class.sealedSubclasses.forEach {
        put(it.objectInstance!!.routePath, true)
    }
} }

渲染时在状态判断里加一层可用校验,onClick里加拦截即可,比如点击首页tab后把我的tab置灰,就在对应逻辑里改tabEnableState["mine"] = false就行。

注意:不要脱离NavController单独维护selectedIndex这类变量控制选中态,否则会出现按系统返回键、深链跳转进入页面时,底部导航状态和实际展示页面不匹配的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:33:08