【问题标题】:Navigation Component, how to show a normal UP/back button instead of hamburger icon in Navigation Drawer导航组件,如何在导航抽屉中显示普通的向上/后退按钮而不是汉堡图标
【发布时间】:2021-09-02 16:37:50
【问题描述】:

我的活动中有三个顶级目的地片段:

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

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

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

谢谢。

【问题讨论】:

  • 导航组件允许基于appBarConfiguration显示或隐藏UP按钮;如果您有自定义设计,则需要恢复以使用 android API 对其进行自定义,在您的情况下,例如 ((requireActivity() as AppCompatActivity).supportActionBar)?.setDisplayHomeAsUpEnabled(boolean)
  • 不幸的是,这不起作用。汉堡图标仍然显示。

标签: android kotlin navigation-drawer android-architecture-components android-navigation


【解决方案1】:

我设法找到了解决方案。我将此变量添加到我的 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,则活动将向上导航,就像正常向上行为一样,并将 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 时,汉堡包图标正常显示,但当以其他方式导航到它时,如按钮,则显示向上按钮:

【讨论】:

  • 这是非常错误和糟糕的代码。您不知道如何将导航组件与工具栏和导航抽屉一起使用。导航组件会自动为您处理此逻辑。但是您决定自己更改图标....
  • @user924 说代码不好而没有提供更好的解决方案对任何人都没有帮助。你介意发布一个更好的答案吗?我不得不想出一些东西,因为我没有找到任何答案。如果您能帮助我做得更好,我将不胜感激。
【解决方案2】:

鉴于:

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

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

必填:

您希望将汉堡保留在主片段 (NutrientFragment) 中,并将其替换为某些片段的 UP 按钮。

解决方案:

假设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 以启用切换功能并导航回 Home 片段(假设 home 片段是 @ 987654344@):

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

预览:

这里的 Gallery 片段是放置 UP 按钮的位置:

【讨论】:

  • 这不是我想要的。我仍然希望所有片段都显示汉堡图标,但如果我以任何其他方式导航到这些片段中的任何一个,而不是抽屉,就像应用程序中的另一个按钮一样,我希望显示向上按钮。但是您的回答帮助我想出了一个解决方案。检查我对帖子的回答,如果可能的话,帮助我做得更好,这是一个解决方案,但有点难看,用户界面有点滞后
  • @hahmraro 这可能完全不同,但它会给你控制汉堡/向上按钮的总体思路.. 自定义完全是你的。
  • @Zain 如何覆盖菜单和返回图标? stackoverflow.com/questions/69812362/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-02
  • 1970-01-01
  • 2022-08-15
相关资源
最近更新 更多