【发布时间】:2020-08-06 14:07:50
【问题描述】:
我正在将我的应用程序转换为使用一个活动并添加了底部导航视图,以防止在片段之间导航时重新创建片段,进行不必要的 api 调用。但是我不能让它工作:
- 没有显示片段
- 图标不切换
- 触摸底部菜单项不会切换片段
- 触摸所选项目会使应用程序崩溃并出现 TypeCastException:
kotlin.TypeCastException: null cannot be cast to non-null type androidx.navigation.fragment.NavHostFragment at com.example.testapp.NavigationExtensionsKt$setupItemReselected$1.onNavigationItemReselected
Activity的布局:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/nav_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
app:menu="@menu/bottom_nav_menu" />
底部导航菜单:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_1"
android:icon="@drawable/ic_1"
android:title="@string/title_1" />
<item
android:id="@+id/homeFragment"
android:icon="@drawable/ic_2"
android:title="@string/home" />
<item
android:id="@+id/navigation_3"
android:icon="@drawable/ic_3"
android:title="@string/title_3" />
</menu>
在 MainActivity 中:
class MainActivity : DaggerAppCompatActivity() {
private var currentNavController: LiveData<NavController>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
nav_view.itemIconTintList = null
if(savedInstanceState == null){
setupBottomNavigationBar()
} // Else, need to wait for onRestoreInstanceState
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
// Now that BottomNavigationBar has restored its instance state
// and its selectedItemId, we can proceed with setting up the
// BottomNavigationBar with Navigation
setupBottomNavigationBar()
}
private fun setupBottomNavigationBar() {
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.nav_view)
val navGraphIds = listOf(R.navigation.mobile_navigation, R.navigation.settings)
val menuItemsIds = listOf(R.id.navigation_1, R.id.homeFragment, R.id.navigation_3)
val defaultIconsIds = listOf(R.drawable.ic_1, R.drawable.ic_2, R.drawable.ic_3)
val selectedIconsIds = listOf(R.drawable.ic_1a, R.drawable.ic_2a, R.drawable.ic_3a)
// Setup the bottom navigation view with a list of navigation graphs (custom extension)
val controller = bottomNavigationView.setupWithNavController(
navGraphIds = navGraphIds,
menuItemsIds = menuItemsIds,
defaultIconsIds = defaultIconsIds,
selectedIconsIds = selectedIconsIds,
fragmentManager = supportFragmentManager,
containerId = R.id.nav_host_container,
intent = intent
)
currentNavController = controller
// updating icons
nav_view.menu.iterator().forEach {
if (it.isChecked) {
it.setIcon(selectedIconsIds[menuItemsIds.indexOf(it.itemId)])
} else {
it.setIcon(defaultIconsIds[menuItemsIds.indexOf(it.itemId)])
}
}
}
override fun onSupportNavigateUp(): Boolean {
return currentNavController?.value?.navigateUp() ?: false
}
}
导航扩展:
//.....
//....
private fun BottomNavigationView.setupItemReselected(
menuItemsIds: List<Int>,
defaultIconsIds: List<Int>,
selectedIconsIds: List<Int>,
graphIdToTagMap: SparseArray<String>,
fragmentManager: FragmentManager) {
setOnNavigationItemReselectedListener { item ->
this.menu.iterator().forEach { it ->
it.setIcon(defaultIconsIds[menuItemsIds.indexOf(it.itemId)])
}
item.setIcon(selectedIconsIds[menuItemsIds.indexOf(item.itemId)])
val newlySelectedItemTag = graphIdToTagMap[item.itemId]
val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag) as NavHostFragment //TypeCastException happens here
val navController = selectedFragment.navController
// Pop the back stack to the start destination of the current navController graph
navController.popBackStack(
navController.graph.startDestination, false
)
}
}
屏幕是空白的,没有渲染任何片段视图。
谁能帮我解决这个问题?我错过了什么吗?
PS:代码取自一个开源应用程序,可以在here找到
[编辑] 添加导航图:
-
mobile_navigation
<fragment
android:id="@+id/homeFragment"
android:name="com.example.testapp.homeFragment"
android:label="@string/home"
tools:layout="@layout/home_fragment" >
<action
android:id="@+id/homrFragment_to_detailsFragment"
app:launchSingleTop="true"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:destination="@id/detailsFragment" />
</fragment>
<fragment
android:id="@+id/navigation_1"
android:name="com.example.testapp.Fragment_S"
android:label="@string/fragment_s"
tools:layout="@layout/fragment_s" >
<action
android:id="@+id/action_navigation_1_to_detailsFragment"
app:destination="@id/detailsFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_in_left" />
</fragment>
<fragment
android:id="@+id/navigation_3"
android:name="com.example.testapp.Fragment3"
android:label="@string/fragment_ss"
tools:layout="@layout/fragment_ss" />
<dialog
android:id="@+id/detailsFragment"
android:name="com.example.testapp.DetailsFragment"
android:label="InDetails"
tools:layout="@layout/layout_details">
<argument
android:name="arg1"
android:defaultValue=""
app:argType="string"/>
<argument
android:name="arg2"
android:defaultValue=""
app:argType="string" />
</dialog>
-
导航设置:
<?xml version="1.0" encoding="utf-8"?>
【问题讨论】:
标签: android android-fragments exception bottomnavigationview kotlin-android-extensions