导航组件,如何在导航抽屉中显示普通 UP/back 按钮而不是汉堡包图标

Navigation Component, how to show a normal UP/back button instead of hamburger icon in Navigation Drawer

我的 activity 中有三个顶级目标片段:

appBarConfiguration = AppBarConfiguration(
        setOf(
            R.id.trackerFragment,
            R.id.nutrientFragment,
            R.id.settingsFragment
        ),
        drawerLayout
    )

这意味着所有这些片段都将显示汉堡包按钮,而不是正常的后退箭头。问题是我的应用程序中有一个“转到营养”按钮,该按钮导航到顶级目的地 NutrientFragment。我希望这个片段在使用抽屉导航时仍然显示汉堡包图标,但在通过“转到营养”按钮导航时显示正常的 back/up 按钮。

我最初的想法是在导航到 NutrientFragment 时传递一个布尔值作为参数,并在 onCreateView() 内部,根据布尔值,删除汉堡包图标或添加后面的按钮。但这似乎有点丑陋和低效,特别是如果将来我添加更多可能有同样问题的目的地。我也不知道如何“删除汉堡包图标并替换为正常的后退按钮”。关于如何实施的任何想法?我找到的所有答案要么是旧的已弃用 java 代码,要么不是我想要的。

谢谢。

给定:

现在您有一个包含三个片段(trackerFragment、nutrientFragment 和 settingsFragment)的导航抽屉。

appBarConfiguration = AppBarConfiguration(
        setOf(
            R.id.trackerFragment,
            R.id.nutrientFragment,
            R.id.settingsFragment
        ),
        drawerLayout
    )

必填:

您想将汉堡保留在主页片段 (NutrientFragment) 中,并将其替换为某些片段的向上按钮。

解法:

假设 settingsFragment 是片段是你需要有向上按钮而不是汉堡。

首先从 appBarConfiguration 中删除此片段:

appBarConfiguration = AppBarConfiguration(
    setOf(
        R.id.trackerFragment, R.id.nutrientFragment
    ), drawerLayout
)

然后,为了控制 Burger 按钮,您需要将抽屉布局和 SupportActionBarActionBarDrawerToggle 同步,这里是方法:

fun getActionBarDrawerToggle(
    drawerLayout: DrawerLayout,
    toolbar: Toolbar
): ActionBarDrawerToggle {
    val toggle = ActionBarDrawerToggle(
        this,
        drawerLayout,
        toolbar,
        R.string.open,
        R.string.close
    )
    drawerLayout.addDrawerListener(toggle)
    toggle.syncState()
    return toggle
}

R.string.open & R.string.close 是符号字符串,可以在 strings.xml:

中创建它们
<resources>
    <string name="open">Open</string>
    <string name="close">Close</string>
</resources>

toolBar 是从布局中膨胀并设置为 supportActionBarsetSupportActionBar()

的工具栏

然后,向导航添加侦听器以检测何时选择 settingFragment,以便您可以使用 toggle.isDrawerIndicatorEnabled:

禁用汉堡的切换功能
val toggle = getActionBarDrawerToggle(drawerLayout, toolbar) // replace  the `drawerLayout` & `toolbar` according to yours
navController.addOnDestinationChangedListener { _, destination, _ ->
    if (destination.id == R.id.settingsFragment)
        toggle.isDrawerIndicatorEnabled = false
}

当然,现在 UP 按钮在您单击它时将不起作用,要解决此问题,我们需要 setToolbarNavigationClickListener 以启用切换功能并导航回主页片段(假设主页片段是 nutrientFragment):

toggle.setToolbarNavigationClickListener {
    toggle.isDrawerIndicatorEnabled = true
    navController.navigate(R.id.nutrientFragment)
}

预览:

这是 Gallery 片段,UP 按钮所在的位置:

我设法找到了解决方案。我将这个变量添加到我的 MainActivity:

// If true, disable drawer and enable back/up button
private var isUpButton = false

还有这些方法:

// Disable drawer and enable the up button
fun useUpButton() {
    supportActionBar?.setHomeAsUpIndicator(
        androidx.appcompat.R.drawable.abc_ic_ab_back_material
    )
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
    isUpButton = true
}

// Enable the drawer and disable up button
private fun useHamburgerButton() {
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
    isUpButton = false
}

useUpButton() 将汉堡包图标替换为默认的向上图标,锁定抽屉滑块并将 isUpButton 设置为 true。我还覆盖了 onOptionsItemsSelected:

// If isUpButton is true, and the home button is clicked, navigate up and
// enable drawer again, if false, just normal drawer behaviour
override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return if (isUpButton && item.itemId == android.R.id.home) {
        navController.navigateUp()
        useHamburgerButton()
        true
    } else super.onOptionsItemSelected(item)
}

因此,如果单击主页按钮(汉堡包图标或向上图标),并且 isUpButton 设置为 true,activity 将向上导航,就像正常的向上行为一样,并将 isUpButton 重置为false,所以其他片段可以再次享受抽屉。

现在我需要做的就是使用这些方法来解决我的问题:我希望 NutrientFragment 仅在我不使用抽屉导航到它时显示“向上按钮”。为此,我需要在 nav_graph.xml:

上为 NutrientFragment 目标创建一个参数
<fragment
    android:id="@+id/nutrientFragment"
    android:name="com.example.elegantcalorietracker.ui.fragments.NutrientFragment"
    android:label="@string/nutrients"
    tools:layout="@layout/fragment_nutrient">
    <action
        android:id="@+id/action_nutrientFragment_to_trackerFragment"
        app:destination="@id/trackerFragment" />
    <argument
        android:name="upButtonNeeded"
        android:defaultValue="false"
        app:argType="boolean" />

并将其添加到 NutrientFragment 的 onCreateView() 方法中:

upButtonNeeded = arguments?.getBoolean("upButtonNeeded") ?: false
if (upButtonNeeded) {
    (activity as MainActivity).useUpButton()
}

现在,如果我在另一个片段中有一个导航到 NutrientFragment 的按钮,我需要做的就是将 true 作为参数传递给导航方法:

val argument = bundleOf("upButtonNeeded" to true)
this@TrackerFragment
     .findNavController()
     .navigate(
         R.id.action_trackerFragment_to_nutrientFragment,
         argument
     )

结果:

当使用抽屉导航到 NutrientFragment 时,汉堡包图标正常显示,但当以其他方式导航到它时,如按钮,向上按钮显示: