替换自定义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
相关产品推荐
相关产品推荐

