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)
}
}
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.