Compose点击底部导航项时修改图标颜色/图标的实现方法
你已经完成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
相关产品推荐
相关产品推荐

