带有 Jetpack Navigation 的 BottomNavigationView 无法正确显示活动菜单指示器
BottomNavigationView with Jetpack Navigation not correctly showing the active menu indicator
-
android
-
android-fragments
-
android-architecture-components
-
android-jetpack-navigation
-
android-bottomnavigationview
我正在尝试使用 Jetpack Navigation 解决 BottomNavigationView
的一些导航问题。我正在使用 Jetpack Navigation 2.4.0-beta02
。第一个问题是后退按钮总是让我回到起始目的地。这个加menuCategory: secondary
就解决了。但是,还有一个问题。
假设我有 BottomNavigationView
的 4 个导航菜单,片段 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。但是,活动菜单指示器仍然在第二个菜单而不是第一个菜单。我希望在第一个菜单中出现活动菜单指示器,因为我从片段 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)
感谢您的帮助!
现在 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)
因此,当您 return 从 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
个片段分开。
更新:
I want when pressing back, it still shows fragment A1 and the indicator is at the 1st menu. Your solution instead navigates me to fragment A.
为此,您通常只弹出返回堆栈一次,并将 BottomNavView
菜单项设置为选中:
假设 BottomNavView
仅由 activity 托管,因此您可以使用 requireActivity() as MainActivity
访问它;将其转换为您的 activity.
的名称
或者,如果它由片段托管,则使用 parentFragment as MyParentFragment
,类似地将其转换为父片段的名称。
在 activity 或父片段:
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()
}
})
android
android-fragments
android-architecture-components
android-jetpack-navigation
android-bottomnavigationview
我正在尝试使用 Jetpack Navigation 解决 BottomNavigationView
的一些导航问题。我正在使用 Jetpack Navigation 2.4.0-beta02
。第一个问题是后退按钮总是让我回到起始目的地。这个加menuCategory: secondary
就解决了。但是,还有一个问题。
假设我有 BottomNavigationView
的 4 个导航菜单,片段 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。但是,活动菜单指示器仍然在第二个菜单而不是第一个菜单。我希望在第一个菜单中出现活动菜单指示器,因为我从片段 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)
感谢您的帮助!
现在 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)
因此,当您 return 从 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
个片段分开。
更新:
I want when pressing back, it still shows fragment A1 and the indicator is at the 1st menu. Your solution instead navigates me to fragment A.
为此,您通常只弹出返回堆栈一次,并将 BottomNavView
菜单项设置为选中:
假设 BottomNavView
仅由 activity 托管,因此您可以使用 requireActivity() as MainActivity
访问它;将其转换为您的 activity.
或者,如果它由片段托管,则使用 parentFragment as MyParentFragment
,类似地将其转换为父片段的名称。
在 activity 或父片段:
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()
}
})