Kotlin 2020 Google's Recommended Solution
Many of these solutions call the Fragment constructor in the Main Activity. However, following Google's recommended pattern, this is not needed.
Setup Navigation Graph Tabs
Firstly create a navigation graph xml for each of your tabs under the res/navigation
directory.
Filename: tab0.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/tab0"
app:startDestination="@id/fragmentA"
tools:ignore="UnusedNavigation">
<fragment
android:id="@+id/fragmentA"
android:label="@string/fragment_A_title"
android:name="com.app.subdomain.fragA"
>
</fragment>
</navigation>
Repeat the above template for your other tabs. Important all fragments and the navigation graph has an id (e.g. @+id/tab0, @+id/fragmentA).
Setup Bottom Navigation View
Ensure the navigation ids are the same as the ones specified on the bottom menu xml.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/fragment_A_title"
android:id="@+id/tab0"
android:icon="@drawable/ic_baseline_book_24"/>
<item android:title="@string/fragment_B_title"
android:id="@+id/tab1"
android:icon="@drawable/ic_baseline_add_alert_24"/>
<item android:title="@string/fragment_C_title"
android:id="@+id/tab2"
android:icon="@drawable/ic_baseline_book_24"/>
<item android:title="@string/fragment_D_title"
android:id="@+id/tab3"
android:icon="@drawable/ic_baseline_more_horiz_24"/>
</menu>
Setup Activity Main XML
Ensure FragmentContainerView
is being used and not <fragment
and do not set the app:navGraph attribute. This will set later in code
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/main_toolbar"
/>
Main Activity XML
Copy over the following Code into your main activity Kotlin file and call setupBottomNavigationBar
within OnCreateView. Ensure you navGraphIds use R.navigation.whatever
and not R.id.whatever
private lateinit var currentNavController: LiveData<NavController>
private fun setupBottomNavigationBar() {
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
val navGraphIds = listOf(R.navigation.tab0, R.navigation.tab1, R.navigation.tab2, R.navigation.tab3)
val controller = bottomNavigationView.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = supportFragmentManager,
containerId = R.id.fragmentContainerView,
intent = intent
)
controller.observe(this, { navController ->
val toolbar = findViewById<Toolbar>(R.id.main_toolbar)
val appBarConfiguration = AppBarConfiguration(navGraphIds.toSet())
NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration)
setSupportActionBar(toolbar)
})
currentNavController = controller
}
override fun onSupportNavigateUp(): Boolean {
return currentNavController?.value?.navigateUp() ?: false
}
Copy NavigationExtensions.kt File
Copy the following file to your codebase
[EDIT] The above link is broken. Found it in a forked repo
Source