【发布时间】:2021-05-20 17:26:35
【问题描述】:
我正在尝试将BottomNavigationView 与Android Navigation 一起使用来创建一个标准的选项卡式应用程序,其中包含三个片段:StatusFragment、MapFragment 和AlertsFragment。
我的main_activity.xml 带有FragmentContainerView 和BottomNavigationView,定义如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/mainNavHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/bottomNavigationView"
app:defaultNavHost="true"
app:navGraph="@navigation/main_nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:menu="@menu/main_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
我的main_nav_graph.xml:
<?xml version="1.0" encoding="utf-8"?>
<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/main_nav_graph"
app:startDestination="@id/mainActivity">
<fragment
android:id="@+id/statusFragment"
android:name="<redacted>.ui.status.StatusFragment"
android:label="StatusFragment" />
<fragment
android:id="@+id/mapFragment"
android:name="<redacted>.ui.map.MapFragment"
android:label="MapFragment" />
<fragment
android:id="@+id/alertsFragment"
android:name="<redacted>.ui.alert.AlertsFragment"
android:label="AlertsFragment" />
<activity
android:id="@+id/mainActivity"
android:name="<redacted>.ui.main.MainActivity"
android:label="main_activity"
tools:layout="@layout/main_activity" />
</navigation>
以及相关联的main_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/statusFragment"
android:icon="@drawable/ic_status_24"
android:title="@string/title_status" />
<item
android:id="@+id/mapFragment"
android:icon="@drawable/ic_map_24"
android:title="@string/title_map" />
<item
android:id="@+id/alertsFragment"
android:icon="@drawable/ic_alert_24"
android:title="@string/title_alerts" />
</menu>
在我MainActivity的onCreate方法中,我配置导航如下:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
binding = MainActivityBinding.inflate(layoutInflater)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.mainNavHostFragment) as NavHostFragment
val navController = navHostFragment.navController
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.statusFragment,
R.id.mapFragment,
R.id.alertsFragment
)
)
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration)
NavigationUI.setupWithNavController(binding.bottomNavigationView, navController)
}
标签栏按预期显示,但点击按钮不会执行任何操作。我确保main_menu.xml 中定义的ids 与main_nav_graph.xml 中的匹配。作为移动导航的一个基本组件,要让它在 Android 上运行被证明是非常困难的。任何帮助将不胜感激。
【问题讨论】:
-
我建议你为你的底部导航实现完全摆脱 JetPack Navigation 并手动配置片段切换或使用 NavGraph 库。因为使用带有喷气背包导航的底部导航会在每次切换标签时强制重新生成片段
-
很抱歉说得这么简单,但@RinatDiushenov 所说的一切都是错误的。使用 Jetpack,它可以工作并且与 Android 的生命周期管理完美集成。如果您使用 Google 提供的正确工具,请不要创建一些错误的自定义实现。
-
@muetzenflo 你是对的 :) 但我想提一下,这并没有说根本不使用喷气背包导航,而是为了避免它用于bottomNavView。您是否认为每次切换选项卡时完全重新创建片段是可以的(可能一遍又一遍地进行昂贵的工作)?因为喷气背包做到了!但是有一些解决方法,需要大量额外的代码。我知道我没有资格提出这种激进的建议,但它是基于 android 世界中众所周知的人所说的话。可以命名Zuinden)
-
@RinatDiushenov 有趣,感谢您的澄清!实际上,我从未遇到重新创建片段的问题(无论是性能还是状态保存)。一个快速“干净”的解决方法可能是将 ViewPager 与 BottomNav 同步。或者通过
saveInstance或使用activitiyViewModel保存片段状态。你知道这种行为背后是否有技术原因吗?还是到目前为止,Google 只是“懒惰”? -
@muetzenflo 据我所知,原因是,在引擎盖下,导航组件使用 replace() 来切换标签。所以可能他们很懒:D
标签: android kotlin android-architecture-navigation android-navigation