Parent Fragment with Navigation Component.
1.Before you begin:
In this blog we will learn how to use Navigation component in a Parent Fragment instead of Activity and navigation within child fragments.
Introduction:
Just like an activity contains Fragments using Navigation component, a Fragment can also contain Fragments with Navigation Component.
In case of using Navigation component in Activity , activity is the parent and all the fragment transactions refer to activity during navigation or Fragments can refer to activity context .
Situation:
Imagine we have a situation where we want a Fragment as Parent and to have child fragments with in them so that the child fragment use ParentFragment context instead of activity context and these fragments are independent of activity.
In this situation, activity will be hosting only Parent Fragment and have no control of Child Fragments.
Where this is useful?
This kind of requirement or solution is useful when we want our child Fragments to be independent of Activity.
This solution is useful when we want to plug and play our app in another activity or we need to host our app in another activity , only parent Fragment will be changed but not any one of its child fragments.
What will this blog do ?
- Create a simple app that uses concept of Parent Fragment
- Parent Fragment hosts 2 child fragments(LoginFragment and ListFragment) with Navigation Component
- Activity hosts only Parent Fragement
- App is developed using Kotlin with Jet Pack components.
Prerequisites:
- Experience with Activities, Fragments.
- Familiarity with the Architecture Components
ViewModel
,LiveData
,Repository
. - Experience with Kotlin syntax, including lambdas.
2.Getting Setup :
The code is available in the above Github repository.
https://github.com/chandragithub2014/ParentFragmentSample.git
3.Run the app:
Once the app is run, we see a login screen followed by list screen. Click back in list screen will navigate to login screen.
How is it implemented?
The code contains below UI components:
(1) MainActivity
(2) ParentFragment
(3) Login Fragment
(4) InfinitListFragment
- MainActivity:
The layout of Main Activity contains a FrameLayout to host the ParentFragment.
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity the below code is used to replace framelayout with ParentFragment.
val parentFragment = ParentFragment.newInstance("","")
supportFragmentManager.beginTransaction().replace(R.id.fragment_container,parentFragment).commit()
2. ParentFragment :
This is the Fragment that hosts child fragment with Navigation component.
Also this Fragment hosts common UI components that can be accessed by its child fragments independent of Activity.
In this example ParentFragment uses ToolBar,which will be used by corresponding child fragments to change the toolbar title during navigation independent of Activity.
ParentFragment instantiates ViewModel which can be accessed by its childFragment without recreating.
The Layout is below:
<androidx.constraintlayout.widget.ConstraintLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<include
layout="@layout/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<fragment
android:id="@+id/nav_host_scanner_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/top_app_bar"
app:navGraph="@navigation/nav_nested"
app:defaultNavHost="true"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Initializing ViewModel in ParentFragment:
private fun initViewModel(){
var infiniteViewModelFactory = InfiniteViewModelFactory()
infiniteListViewModel = ViewModelProvider(this,infiniteViewModelFactory).get(
InfiniteListViewModel::class.java)
}
How to access ParentFragment toolbar view in child Fragments . Below is the code fragment how it’s accessed in LoginFragment to change title.
LoginFragment:
private fun initToolBar(){
val navHostFragment = parentFragment as NavHostFragment?
navHostFragment?.let { navHostFragment ->
navHostFragment.parentFragment?.let { parentFrag ->
var toolbar = parentFrag.view?.findViewById<MaterialToolbar>(R.id.top_app_bar)
toolbar?.title = "Login Form"
}
}
}
override fun onResume() {
super.onResume()
initToolBar()
}
Accessing ParentFragment Viewmodel in childFragment.
private fun initViewModel(){
nfiniteListViewModel = ViewModelProvider(requireParentFragment().requireParentFragment()).get<InfiniteListViewModel>()
}
BackNavigation in ChildFragment using hardware back button:
In order to achieve back navigation in childFragment using hardware backbutton , we need to use callback that uses activity instance. This is the only scenario where we use activity instance in child fragment.
The below code fragment shows how backnavigation happens from list fragment to login screen fragment using onBackPressedcallback method :
val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
NavHostFragment.findNavController(this@InfiniteListFragment).navigateUp()
}
}
requireActivity().onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
Conclusion:
This is how we can use ParentFragment with Navigationcomponent independent of Activity.