I tried implementing the bottom navigation view to set up with fragment transition using navigation components by referring Navigation Codelab.
The fragments are not changing when clicking on the bottom navigation view.
Note:
I am trying to implement the bottom navigation view inside another fragment. (Not an activity like in the codelab example)
MainActivity.kt:
class MainActivity : AppCompatActivity() {
// Data binding
private lateinit var mainActivityBinding: MainActivityBinding
// On activity creation starting
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set activity layout
mainActivityBinding = DataBindingUtil.setContentView(this, R.layout.main_activity)
}
}
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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"
tools:context=".activity.MainActivity">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main_activity_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/main_activity_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/activity_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
activity_navigation.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/activity_navigation"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.appz.abhi.moneytracker.view.main.MainFragment"
android:label="main_fragment"
tools:layout="@layout/main_fragment" />
</navigation>
MainFragment.kt:
class MainFragment : Fragment() {
// Data binding
private var mainFragmentBinding: MainFragmentBinding? = null
// On fragment view creation starting
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the fragment layout
mainFragmentBinding = DataBindingUtil
.inflate(inflater, R.layout.main_fragment, container, false)
// Return root view
return mainFragmentBinding!!.root
}
// On fragment view creation completion
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Initialize UI
initUI()
}
// Initialize UI
private fun initUI() {
// Setup action bar
(activity as AppCompatActivity).setSupportActionBar(mainFragmentBinding?.mainFragmentToolbar)
// Setup bottom navigation view
setUpBottomNavigationView()
}
// Setup bottom navigation view
private fun setUpBottomNavigationView() {
// Nav host fragment
val host: NavHostFragment = activity?.supportFragmentManager
?.findFragmentById(R.id.main_fragment_nav_host_fragment) as NavHostFragment?
?: return
// Set up Action Bar
val navController = host.navController
// Setup bottom navigation view
mainFragmentBinding?.mainFragmentBottomNavigationView?.setupWithNavController(navController)
}
}
main_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout 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"
tools:context=".view.main.MainFragment">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main_fragment_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/main_fragment_app_bar_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/main_fragment_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@drawable/toolbar_background"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
tools:title="Money Tracker" />
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="@+id/main_fragment_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/main_fragment_app_bar_layout"
app:navGraph="@navigation/bottom_navigation_view_navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/main_fragment_bottom_navigation_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/white"
app:itemIconTint="@color/bottom_navigation"
app:itemTextColor="@color/bottom_navigation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/bottom_navigation_view_menu"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
bottom_navigation_view_navigation.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/bottom_navigation_view_navigation"
app:startDestination="@id/settingsFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.appz.abhi.moneytracker.view.home.HomeFragment"
android:label="Home"
tools:layout="@layout/home_fragment" />
<fragment
android:id="@+id/settingsFragment"
android:name="com.appz.abhi.moneytracker.view.settings.SettingsFragment"
android:label="Settings"
tools:layout="@layout/settings_fragment" />
</navigation>
bottom_navigation_view_menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@id/homeFragment"
android:icon="@drawable/ic_home_black_24dp"
android:title="@string/home"
app:showAsAction="ifRoom" />
<item
android:id="@id/settingsFragment"
android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/settings"
app:showAsAction="ifRoom" />
</menu>
HomeFragment.kt:
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.home_fragment, container, false)
}
}
SettingsFragment.kt:
class SettingsFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.settings_fragment, container, false)
}
}
If you run the code, you can see that the bottom navigation works perfectly. We do not need to create adapter and switch the fragment manually when bottom menu item is clicked. Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +756K followers.
NOTE: Refer Android Setup BottomNavigationView With Jetpack Navigation UI (Kotlin). We shall create an Activity with BottomNavigationView which switches the main view the fragments. You can create a Bottom Navigation Activity using Android Studio wizard: File -> New -> Activity -> Bottom Navigation Activity.
Setting up bottom navigation is super easy too. Just create bottom_menu for bottom navigation. And add BottomNavigationView in container_main of the activity_main layout. Finally override onOptionsItemSelected method and call onNavDestinationSelected to handle bottomNavigation item click in the MainActivity. And that’s it.
Finally override onOptionsItemSelected method and call onNavDestinationSelected to handle bottomNavigation item click in the MainActivity. And that’s it. If you run the code, you can see that the bottom navigation works perfectly. We do not need to create adapter and switch the fragment manually when bottom menu item is clicked.
It doesn't seem like you ever get to the setupWithNavController
line. You use findFragmentById(R.id.main_fragment_nav_host_fragment)
with the activity's FragmentManager, but the NavHostFragment in the activity is under the id main_activity_nav_host_fragment
. You should be using childFragmentManager
if you want to get the nested NavHostFragment
in your MainFragment
's layout:
// Nav host fragment
val host: NavHostFragment = childFragmentManager
.findFragmentById(R.id.main_fragment_nav_host_fragment) as NavHostFragment?
?: return
Note that there are very few cases where you actually want or need a nested NavHostFragment
like this. As per the Listen for navigation events documentation, generally if you want global navigation such as a BottomNavigationView
to only appear on some screens, you'd add an OnDestinationChangedListener
and change its visibility there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With