带有 Jetpack Navigation 的 BottomNavigationView 未正确显示活动菜单指示器
Posted
技术标签:
【中文标题】带有 Jetpack Navigation 的 BottomNavigationView 未正确显示活动菜单指示器【英文标题】:BottomNavigationView with Jetpack Navigation not correctly showing the active menu indicator 【发布时间】:2021-12-22 07:44:34 【问题描述】:我正在尝试使用 Jetpack Navigation 解决 BottomNavigationView
的一些导航问题。我正在使用 Jetpack Navigation 2.4.0-beta02
。第一个问题是后退按钮总是将我导航回起始目的地。这个通过添加menuCategory: secondary
来解决。但是,还有另一个问题。
假设我有 4 个导航菜单 BottomNavigationView
,片段 A、B、C 和 D。然后,还有另一个片段 A1,它不属于 BottomNavigationView
。导航图如下所示:
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/navigation_a">
<fragment
android:id="@+id/navigation_a"
android:name="com.example.FragmentA"
android:label=""
tools:layout="@layout/fragment_a">
<action
android:id="@+id/action_navigation_a_to_navigation_a1"
app:destination="@id/navigation_a1"
app:launchSingleTop="true" />
</fragment>
<fragment
android:id="@+id/navigation_a1"
android:name="com.example.FragmentA1"
android:label=""
tools:layout="@layout/fragment_a1" />
<fragment
android:id="@+id/navigation_b"
android:name="com.example.FragmentB"
android:label=""
tools:layout="@layout/fragment_b" />
<fragment
android:id="@+id/navigation_c"
android:name="com.example.FragmentC"
android:label=""
tools:layout="@layout/fragment_c" />
<fragment
android:id="@+id/navigation_d"
android:name="com.example.FragmentD"
android:label=""
tools:layout="@layout/fragment_d" />
</navigation>
所以,如果我从片段 A 导航到 A1,然后导航到片段 B(现在活动菜单指示器位于第二个菜单),然后我按下硬件返回按钮,它显示片段 A1 是正确的。但是,活动菜单指示器仍位于第 2 个菜单而不是第 1 个菜单。我希望在第一个菜单中出现活动菜单指示器,因为我从片段 A 导航到片段 A1。
这是我的menu.xml
文件
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_a"
android:title="A"
android:menuCategory="secondary" />
<item
android:title="B"
android:id="@+id/navigation_b"
android:menuCategory="secondary" />
<item
android:title="C"
android:id="@+id/navigation_c"
android:menuCategory="secondary" />
<item
android:title="D"
android:id="@+id/navigation_d"
android:menuCategory="secondary" />
</menu>
和MainActivity.kt
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment
navController = navHostFragment.navController
binding.navView.setupWithNavController(navController)
感谢您的帮助!
【问题讨论】:
【参考方案1】:现在BottomNavigationView
有 4 个片段:A、B、C 和 D。
你想让导航像:
A (A highlighted) -> A1 -> B (A highlighted) -> Back pressed -> A1 (A highlighted)
但是你得到了:
A (A highlighted) -> A1 -> B (A highlighted) -> Back pressed -> A1 (B highlighted)
所以,当您从 B 返回时,您需要突出显示 A。
要做到这一点,当在片段 B 处按下后退时,您需要检查后退堆栈中的前一个片段。
伪代码:
// At fragment B
if (back_pressed)
if (previous_fragment is A1)
popup the back stack twice to return back to A
else
popup the back stack once (Normal behavior of the back stack)
代码:
class FragmentB : Fragment()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View?
val view = inflater.inflate(R.layout.fragment_b, container, false)
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner,
object : OnBackPressedCallback(true)
override
fun handleOnBackPressed() // Back pressed
val previousFragment = findNavController().previousBackStackEntry?.destination?.id
previousFragment?.let
when (previousFragment)
R.id.navigation_a1 ->
findNavController().navigateUp()
else ->
Log.d(TAG, "onCreateView: Not A1")
findNavController().navigateUp() // Normal behaviour when back is pressed
)
return view
旁注:
这适用于当前的navGraph
设置;但我鼓励你有另一个图表,甚至是当前图表中的嵌套导航;这样您就可以将片段 A1 与 BottomNavView
片段分开。
更新:
我希望当按下返回时,它仍然显示片段 A1,并且指示器位于第一个菜单。相反,您的解决方案将我导航到片段 A。
为此,您通常只弹出一次返回堆栈,并设置要检查的BottomNavView
菜单项:
假设BottomNavView
仅由活动托管,因此您可以使用requireActivity() as MainActivity
访问它;将其转换为您的活动名称。
或者,如果它由片段托管,则使用parentFragment as MyParentFragment
,类似地将其转换为父片段的名称。
在活动或父片段:
fun highlightAItem()
// Highlight A item from the bottomNavView
val item = navView.menu.findItem(R.id.navigation_a)
item.isChecked = true
在片段 B:
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner,
object : OnBackPressedCallback(true)
override
fun handleOnBackPressed()
// Highlight A item from the BottomNavView
(requireActivity() as MainActivity).highlightAItem()
// Pop backstack once to return to A1 fragment
findNavController().navigateUp()
)
【讨论】:
抱歉迟到了,我认为解决方案不符合我的期望。我想按下回时,它仍然显示片段 A1 并且指示器位于第一个菜单。相反,您的解决方案将我导航到片段 A。 对不起,如果您误解了;让我再想想 @BernhardJosephus 请查看更新后的答案UPDATE
部分。
对不起,我刚刚有时间检查它,它有效。非常感谢你的帮助! ^^以上是关于带有 Jetpack Navigation 的 BottomNavigationView 未正确显示活动菜单指示器的主要内容,如果未能解决你的问题,请参考以下文章