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

替换自定义View后,如何设置Android BottomNavigationView选中项颜色?

问题

使用默认BottomNavigationView时,第一个菜单项能正常显示status_selected的选中状态;但替换为自定义View后,尽管第一个Fragment已正常创建,对应的菜单项却始终显示未选中状态的颜色。如何让第一个菜单项呈现选中的外观?

代码实现(MainFragment.kt)

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
    _binding = FragmentMainBinding.inflate(inflater, container, false)
        .apply {
            setBottomNavigation(bottomNaviView)
        }
    return binding.root
}

private fun setBottomNavigation(bottomNavView: BottomNavigationView) = bottomNavView.run {
    val menus = menu
    for (i in 0 until menus.size) {
        val item = menus.getItem(i)
        replaceBottomNavItemWithCustomView(this, item)
    }
    setOnItemSelectedListener(navItemSelectListener)
}

private fun replaceBottomNavItemWithCustomView(bottomNavView: BottomNavigationView, item: MenuItem) {
    val itemView = bottomNavView.findViewById<View>(item.itemId) as ViewGroup
    val customView = LayoutInflater.from(requireContext()).inflate(R.layout.bottom_nav_item, null)
    customView.findViewById<ImageView>(R.id.icon).setImageDrawable(item.icon)
    customView.findViewById<TextView>(R.id.label).text = item.title.toString()
    itemView.removeAllViews()
    itemView.addView(customView)
}

已尝试的方法

  • 在onViewCreated中执行:binding.bottomNaviView.menu.getItem(0).isChecked = true
  • 在replaceBottomNavItemWithCustomView函数中添加以下代码:
customView.findViewById<ImageView>(R.id.icon).run {
    imageTintList = item.iconTintList
    setImageDrawable(item.icon)
    if (item.itemId == R.id.first_item_id) item.isChecked = true
}
customView.findViewById<TextView>(R.id.label).run {
    setTextColor(item.iconTintList)
    text = item.title.toString()
}

可行解决方案

核心原因

自定义View不会自动绑定BottomNavigationView的选中状态变化逻辑,需要手动同步选中/未选中的样式。

方案1:手动同步样式+默认选中设置

步骤1:提取样式更新逻辑

新增统一更新自定义View样式的方法,根据选中状态切换颜色:

private fun updateNavItemStyle(icon: ImageView, label: TextView, isSelected: Boolean) {
    val selectedColor = ContextCompat.getColor(requireContext(), R.color.status_selected)
    val unselectedColor = ContextCompat.getColor(requireContext(), R.color.status_unselected)
    val color = if (isSelected) selectedColor else unselectedColor
    
    icon.imageTintList = ColorStateList.valueOf(color)
    label.setTextColor(color)
}

步骤2:初始化时设置默认选中样式

修改replaceBottomNavItemWithCustomView,初始化时判断是否为第一个item并设置对应样式:

private fun replaceBottomNavItemWithCustomView(bottomNavView: BottomNavigationView, item: MenuItem) {
    val itemView = bottomNavView.findViewById<View>(item.itemId) as ViewGroup
    val customView = LayoutInflater.from(requireContext()).inflate(R.layout.bottom_nav_item, null)
    
    val icon = customView.findViewById<ImageView>(R.id.icon)
    val label = customView.findViewById<TextView>(R.id.label)
    
    // 初始化样式:第一个item默认选中
    val isDefaultSelected = item.itemId == R.id.first_item_id
    updateNavItemStyle(icon, label, isDefaultSelected)
    
    icon.setImageDrawable(item.icon)
    label.text = item.title.toString()
    
    // 绑定点击事件,触发BottomNavigationView的选中逻辑
    customView.setOnClickListener {
        bottomNavView.selectedItemId = item.itemId
    }
    
    itemView.removeAllViews()
    itemView.addView(customView)
}

步骤3:在选中回调中同步所有item样式

修改navItemSelectListener,每次选中时更新所有菜单项的样式:

private val navItemSelectListener = BottomNavigationView.OnItemSelectedListener { selectedItem ->
    // 遍历所有菜单项,更新选中状态样式
    for (i in 0 until binding.bottomNaviView.menu.size) {
        val menuItem = binding.bottomNaviView.menu.getItem(i)
        val itemView = binding.bottomNaviView.findViewById<ViewGroup>(menuItem.itemId)
        val icon = itemView.findViewById<ImageView>(R.id.icon)
        val label = itemView.findViewById<TextView>(R.id.label)
        
        updateNavItemStyle(icon, label, menuItem.itemId == selectedItem.itemId)
    }
    
    // 处理Fragment切换逻辑
    when(selectedItem.itemId) {
        R.id.first_item_id -> // 切换到第一个Fragment
        // 其他菜单项的Fragment切换逻辑
    }
    true
}

步骤4:强制设置默认选中

在setBottomNavigation末尾添加默认选中代码,确保状态同步:

private fun setBottomNavigation(bottomNavView: BottomNavigationView) = bottomNavView.run {
    val menus = menu
    for (i in 0 until menus.size) {
        val item = menus.getItem(i)
        replaceBottomNavItemWithCustomView(this, item)
    }
    setOnItemSelectedListener(navItemSelectListener)
    // 强制选中第一个item
    selectedItemId = R.id.first_item_id
}

方案2:利用Menu状态监听(简化版)

如果不想手动遍历,也可以给BottomNavigationView设置选中/重选回调,在回调中直接更新当前选中和之前选中的item样式。不过方案1的遍历方式更稳妥,适配自定义View的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:53:19