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

Android NavigationView导航抽屉Bug:部分未选中项文本莫名加粗

问题描述

使用Android NavigationView实现导航抽屉时,当菜单包含15个以上选项,选中某一项后,随机有1-2个未选中项的文本变为粗体。

相关代码

<com.google.android.material.navigation.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="@color/colorMenuBg"
    android:fitsSystemWindows="true"
    android:maxWidth="268dp"
    app:headerLayout="@layout/nav_header"
    app:menu="@menu/nav_menu"
    app:itemHorizontalPadding="28dp"
    app:itemIconPadding="18dp"
    app:itemIconSize="24dp"
    app:itemIconTint="@drawable/drawer_item"
    app:itemTextColor="@drawable/drawer_item">

菜单项示例代码

<item
    android:id="@+id/nav_videos"
    android:icon="@drawable/cat_icon_videos"
    android:checkable="true"
    android:title="@string/all_videos"/>
<item
    android:id="@+id/nav_pics"
    android:icon="@drawable/cat_icon_gallery"
    android:checkable="true"
    android:title="@string/all_pics"/>
<item
    android:id="@+id/nav_gifs"
    android:icon="@drawable/cat_icon_gif"
    android:checkable="true"
    android:title="@string/all_gifs"/>

当前onNavigationItemSelected代码片段

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    when (item.itemId) {
        R.id.nav_latest -> {
            if (currentGal != "latest") {
                getMemes("latest")
            }
        }
        R.id.nav_top -> {
            if (currentGal != "top") {
                getMemes("top")
            }
        }
        R.id.nav_random -> {
            if (currentGal != "random") {
                getMemes("random")
            }
        }

解决方案

这个问题是NavigationView内部RecyclerView的View Holder复用导致的视图状态错乱,菜单选项过多时触发复用,未正确重置非选中项的文本样式。以下是几种可行修复方案:

1. 启用菜单单选模式

在nav_menu.xml的根<menu>标签中添加单选行为配置,让系统自动管理选中状态:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    android:checkableBehavior="single">
    <!-- 所有菜单项 -->
</menu>

2. 在onNavigationItemSelected中手动重置所有项样式

通过遍历菜单项,强制设置选中/未选中状态的文本样式,解决复用导致的错乱:

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    // 遍历所有菜单项,重置选中状态与文本样式
    for (i in 0 until nav_view.menu.size()) {
        val menuItem = nav_view.menu.getItem(i)
        val isSelected = menuItem.itemId == item.itemId
        menuItem.isChecked = isSelected
        
        // 设置文本样式:选中为粗体,未选中为正常
        menuItem.title = SpannableString(menuItem.title).apply {
            setSpan(
                StyleSpan(if (isSelected) Typeface.BOLD else Typeface.NORMAL),
                0,
                length,
                Spannable.SPAN_INCLUSIVE_INCLUSIVE
            )
        }
    }

    // 原有业务逻辑保留
    when (item.itemId) {
        R.id.nav_latest -> {
            if (currentGal != "latest") {
                getMemes("latest")
            }
        }
        R.id.nav_top -> {
            if (currentGal != "top") {
                getMemes("top")
            }
        }
        R.id.nav_random -> {
            if (currentGal != "random") {
                getMemes("random")
            }
        }
        // 其他菜单项处理
    }

    // 关闭导航抽屉
    findViewById<DrawerLayout>(R.id.drawer_layout).closeDrawer(GravityCompat.START)
    return true
}

3. 自定义MenuItem文本样式

通过样式文件明确区分选中与未选中的文本样式,避免复用冲突:
在styles.xml中定义样式:

<style name="NavItemTextNormal">
    <item name="android:textSize">14sp</item>
    <item name="android:textStyle">normal</item>
</style>

<style name="NavItemTextSelected">
    <item name="android:textStyle">bold</item>
</style>

在NavigationView布局中引用:

<com.google.android.material.navigation.NavigationView
    ...
    app:itemTextAppearance="@style/NavItemTextNormal"
    app:itemTextAppearanceSelected="@style/NavItemTextSelected"
    ...>

关于onNavigationItemSelected修复的可行性

可以,通过修改onNavigationItemSelected方法能直接解决问题,核心是手动重置所有菜单项的状态与样式,覆盖View复用带来的异常。上面的方案2就是基于该方法的具体实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:09:26