I create this fragment and set initial fragment FirstFragment, if I don't set this initial fragment, the app will crash.
<fragment
android:id="#+id/fragment"
android:name="com.app.FirstFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp" />
And then I use this function to replace the fragment, this works fine, every fragment can be replaced by other fragment except FirstFragment, this fragment keep displaying on screen. How can I replace this fragment?
enum class FragmentType {
SETTING, ACTIVITY, PROFILE, CONNECT, SCANNER
}
private fun changeFragmentTo(type: FragmentType) {
val transaction = supportFragmentManager.beginTransaction()
when(type) {
FragmentType.SETTING -> {
title = "SETTING"
val f = SettingFragment()
transaction.replace(R.id.fragment, f)
}
FragmentType.ACTIVITY -> {
title = "ACTIVITY"
val f = ActivityFragment()
transaction.replace(R.id.fragment, f)
}
FragmentType.PROFILE -> {
title = "PROFILE"
val f = ProfileFragment()
transaction.replace(R.id.fragment, f)
}
FragmentType.CONNECT -> {
title = "CONNECT"
val f = ConnectFragment()
transaction.replace(R.id.fragment, f)
}
FragmentType.SCANNER -> {
title = "SCANNER"
val f = ScannerFragment()
transaction.replace(R.id.fragment, f)
}
}
transaction.addToBackStack(null)
transaction.commit()
}
The problem of yours is inside the xml. Instead of using fagment tag, you should create a layout which will be a container for your fragment.
Change your xml like this:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
and reference your FrameLayout inside, I assume, activity via it's id R.id.fragment:
val fragment = SettingFragment()
transaction.replace(R.id.fragment_container, fragment)
Related
I'm using Bottom navigation Bar and Kakao Login API. When I choose account menu in bottom bar if I need login then replace fragment to fragmentAccount else I don't need login then replace fragmnet to fragment2Account. I tried to do this but it makes Error. I want to know why it makes error and how can fix this.
val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
val fragmentAccount = AccountFragment()
val fragment2Account = Account2Fragment()
when(p0.itemId){
R.id.account -> {
if (AuthApiClient.instance.hasToken()) {
UserApiClient.instance.accessTokenInfo { _, error ->
if (error != null) {
transaction.replace(R.id.frame, fragmentAccount, "Account")
}
else transaction.replace(R.id.frame, fragment2Account, "Account")
}
}
else transaction.replace(R.id.frame, fragmentAccount, "Account")
}
}
transaction.addToBackStack(null)
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
transaction.commit()
return true
Error code ↓↓↓
kotlin.UninitializedPropertyAccessException: lateinit property hosts has not been initialized
When I use backStackEntryCount > 1. popbackstack() it is not navigating to any of the fragments of my bottom navigation
What I need to know is, how to stack fragments one time only, so I can press the back button once which will be navigating to the Activity.
private fun navBottomClick() {
bottomNavigationView?.setOnItemSelectedListener {
when (it.itemId) {
R.id.workout -> {
var fragmentTransaction: FragmentTransaction =
supportFragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.container, WorkoutFragment(), "WORKOUT")
fragmentTransaction.addToBackStack("WORKOUT")
fragmentTransaction.commit()
}
R.id.health -> {
var fragmentTransaction: FragmentTransaction =
supportFragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.container, HealthyFoodFragment(), "HealthFood")
fragmentTransaction.addToBackStack("HealthFood")
fragmentTransaction.commit()
}
}
true
}
}
without backStack you can try this
override fun onBackPressed() {
if (binding.bottomNavigation.selectedItemId == R.id.home) {
moveTaskToBack(true)
} else {
binding.bottomNavigation.selectedItemId = R.id.home
val homeFragment = HomeFragment.newInstance()
openFragment(homeFragment)
}
}
Try to print log supportFragmentManager.backStackEntryCount.
And my opinion is the condition is supportFragmentManager.backStackEntryCount > 0.
I have been using Android Advanced Navigation for a while. In my current project, I have three navigation graphs. The problem is, some of the fragments in one graph should be reached from another graph. In order to solve this, I've made deep links.
For example, in graph A I've included graph B and then used a deep link from graph B to reach that particular fragment. The problem is when I am in graph B and now I want to jump back to graph A I can't. As graph A is not included in graph B, the current navigation controller can't find the destination. If I include graph A in graph B, another problem occurs. Android Studio can't build the project as it is having a circular import problem (graph B tries to import graph A but graph B is already included in graph A etc.) and I really don't know what else to do.
I've tried creating one huge navigation graph which contains all three subgraphs but I couldn't make it work with this Android Advanced Navigation. Is there any more efficient way?
Edit to add code:
BottomNavigationView extension:
fun BottomNavigationView.setupWithNavController(
navGraphIds: List<Int>,
fragmentManager: FragmentManager,
containerId: Int,
intent: Intent
): LiveData<NavController> {
// Map of tags
val graphIdToTagMap = SparseArray<String>()
// Result. Mutable live data with the selected controlled
val selectedNavController = MutableLiveData<NavController>()
var firstFragmentGraphId = 0
// First create a NavHostFragment for each NavGraph ID
navGraphIds.forEachIndexed { index, navGraphId ->
val fragmentTag = getFragmentTag(index)
// Find or create the Navigation host fragment
val navHostFragment = obtainNavHostFragment(
fragmentManager,
fragmentTag,
navGraphId,
containerId
)
// Obtain its id
val graphId = navHostFragment.navController.graph.id
if (index == 0) {
firstFragmentGraphId = graphId
}
// Save to the map
graphIdToTagMap[graphId] = fragmentTag
// Attach or detach nav host fragment depending on whether it's the selected item.
if (this.selectedItemId == graphId) {
// Update livedata with the selected graph
selectedNavController.value = navHostFragment.navController
attachNavHostFragment(fragmentManager, navHostFragment, index == 0)
} else {
detachNavHostFragment(fragmentManager, navHostFragment)
}
}
// Now connect selecting an item with swapping Fragments
var selectedItemTag = graphIdToTagMap[this.selectedItemId]
val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId]
var isOnFirstFragment = selectedItemTag == firstFragmentTag
// When a navigation item is selected
setOnNavigationItemSelectedListener { item ->
// Don't do anything if the state is state has already been saved.
if (fragmentManager.isStateSaved) {
false
} else {
val newlySelectedItemTag = graphIdToTagMap[item.itemId]
if (selectedItemTag != newlySelectedItemTag) {
// Pop everything above the first fragment (the "fixed start destination")
fragmentManager.popBackStack(firstFragmentTag,
FragmentManager.POP_BACK_STACK_INCLUSIVE)
val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag)
as NavHostFragment
// Exclude the first fragment tag because it's always in the back stack.
if (firstFragmentTag != newlySelectedItemTag) {
// Commit a transaction that cleans the back stack and adds the first fragment
// to it, creating the fixed started destination.
fragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.nav_default_enter_anim,
R.anim.nav_default_exit_anim,
R.anim.nav_default_pop_enter_anim,
R.anim.nav_default_pop_exit_anim)
.attach(selectedFragment)
.setPrimaryNavigationFragment(selectedFragment)
.apply {
// Detach all other Fragments
graphIdToTagMap.forEach { _, fragmentTagIter ->
if (fragmentTagIter != newlySelectedItemTag) {
detach(fragmentManager.findFragmentByTag(firstFragmentTag)!!)
}
}
}
.addToBackStack(firstFragmentTag)
.setReorderingAllowed(true)
.commit()
}
selectedItemTag = newlySelectedItemTag
isOnFirstFragment = selectedItemTag == firstFragmentTag
selectedNavController.value = selectedFragment.navController
true
} else {
false
}
}
}
// Optional: on item reselected, pop back stack to the destination of the graph
setupItemReselected(graphIdToTagMap, fragmentManager)
// Handle deep link
setupDeepLinks(navGraphIds, fragmentManager, containerId, intent)
// Finally, ensure that we update our BottomNavigationView when the back stack changes
fragmentManager.addOnBackStackChangedListener {
if (!isOnFirstFragment && !fragmentManager.isOnBackStack(firstFragmentTag)) {
this.selectedItemId = firstFragmentGraphId
}
// Reset the graph if the currentDestination is not valid (happens when the back
// stack is popped after using the back button).
selectedNavController.value?.let { controller ->
if (controller.currentDestination == null) {
controller.navigate(controller.graph.id)
}
}
}
return selectedNavController
}
private fun BottomNavigationView.setupDeepLinks(
navGraphIds: List<Int>,
fragmentManager: FragmentManager,
containerId: Int,
intent: Intent
) {
navGraphIds.forEachIndexed { index, navGraphId ->
val fragmentTag = getFragmentTag(index)
// Find or create the Navigation host fragment
val navHostFragment = obtainNavHostFragment(
fragmentManager,
fragmentTag,
navGraphId,
containerId
)
// Handle Intent
if (navHostFragment.navController.handleDeepLink(intent)
&& selectedItemId != navHostFragment.navController.graph.id) {
this.selectedItemId = navHostFragment.navController.graph.id
}
}
}
private fun BottomNavigationView.setupItemReselected(
graphIdToTagMap: SparseArray<String>,
fragmentManager: FragmentManager
) {
setOnNavigationItemReselectedListener { item ->
val newlySelectedItemTag = graphIdToTagMap[item.itemId]
val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag)
as NavHostFragment
val navController = selectedFragment.navController
// Pop the back stack to the start destination of the current navController graph
navController.popBackStack(
navController.graph.startDestination, false
)
}
}
private fun detachNavHostFragment(
fragmentManager: FragmentManager,
navHostFragment: NavHostFragment
) {
fragmentManager.beginTransaction()
.detach(navHostFragment)
.commitNow()
}
private fun attachNavHostFragment(
fragmentManager: FragmentManager,
navHostFragment: NavHostFragment,
isPrimaryNavFragment: Boolean
) {
fragmentManager.beginTransaction()
.attach(navHostFragment)
.apply {
if (isPrimaryNavFragment) {
setPrimaryNavigationFragment(navHostFragment)
}
}
.commitNow()
}
private fun obtainNavHostFragment(
fragmentManager: FragmentManager,
fragmentTag: String,
navGraphId: Int,
containerId: Int
): NavHostFragment {
// If the Nav Host fragment exists, return it
val existingFragment = fragmentManager.findFragmentByTag(fragmentTag) as NavHostFragment?
existingFragment?.let { return it }
// Otherwise, create it and return it.
val navHostFragment = NavHostFragment.create(navGraphId)
fragmentManager.beginTransaction()
.add(containerId, navHostFragment, fragmentTag)
.commitNow()
return navHostFragment
}
private fun FragmentManager.isOnBackStack(backStackName: String): Boolean {
val backStackCount = backStackEntryCount
for (index in 0 until backStackCount) {
if (getBackStackEntryAt(index).name == backStackName) {
return true
}
}
return false
}
private fun getFragmentTag(index: Int) = "bottomNavigation#$index"
Navigation graphs:
<?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/home_nav_graph"
app:startDestination="#id/homeFragment">
<fragment
android:id="#+id/homeFragment"
android:name="lu.thebiggame.fragments.home.HomeFragment"
android:label="home_fragment"
tools:layout="#layout/home_fragment" >
<action
android:id="#+id/homeToGameResults"
app:destination="#id/gameResultsFragment" />
<action
android:id="#+id/homeToPlayLottoGames"
app:destination="#id/playLottoGamesFragment" />
</fragment>
<fragment
android:id="#+id/checkoutFragment"
tools:layout="#layout/checkout_fragment"
android:name="lu.thebiggame.fragments.checkout.CheckoutFragment"
android:label="CheckoutFragment" />
<fragment
android:id="#+id/gameResultsFragment"
android:name="lu.thebiggame.fragments.gameresults.GameResultsFragment"
android:label="game_results_fragment"
tools:layout="#layout/game_results_fragment">
<deepLink
android:id="#+id/gameResultsFragmentDeepLink"
app:uri="app://home/game-results-fragment" />
<action
android:id="#+id/gameResultsToPlayLottoGames"
app:destination="#id/playLottoGamesFragment" />
</fragment>
<fragment
android:id="#+id/congratulationsFragment"
android:name="lu.thebiggame.fragments.congratulations.CongratulationsFragment"
android:label="congratulations_fragment"
tools:layout="#layout/congratulations_fragment" >
<action
android:id="#+id/congratulationsToClaim"
app:destination="#id/claimFragment" />
<deepLink
android:id="#+id/congratulationsFragmentDeepLink"
app:uri="app://home/congratulations-fragment" />
</fragment>
<fragment
android:id="#+id/claimFragment"
tools:layout="#layout/claim_fragment"
android:name="lu.thebiggame.fragments.claim.ClaimFragment"
android:label="ClaimFragment" />
<include app:graph="#navigation/profile_nav_graph"/>
<fragment
android:id="#+id/aboutGameFragment"
android:name="lu.thebiggame.fragments.page.PageFragment"
android:label="page_fragment"
tools:layout="#layout/page_fragment">
<deepLink
android:id="#+id/aboutGameFragmentDeepLink"
app:uri="app://home/about-game-fragment" />
</fragment>
<fragment
android:id="#+id/playLottoGamesFragment"
android:name="lu.thebiggame.fragments.play.lottogames.PlayLottoGamesFragment"
tools:layout="#layout/play_lotto_games_fragment"
android:label="PlayLottoGamesFragment" >
<action
android:id="#+id/playLottoGamesToCheckout"
app:destination="#id/checkoutFragment" />
<deepLink
android:id="#+id/playLottoGamesDeepLink"
app:uri="app://home/play-lotto-games-fragment" />
<action
android:id="#+id/playLottoGamesToGameResults"
app:destination="#id/gameResultsFragment" />
</fragment>
</navigation>
<?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/games_nav_graph"
app:startDestination="#id/gamesFragment">
<fragment
android:id="#+id/gamesFragment"
android:name="lu.thebiggame.fragments.games.GamesFragment"
android:label="games_fragment"
tools:layout="#layout/games_fragment" />
<include app:graph="#navigation/home_nav_graph"/>
</navigation>
<?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/profile_nav_graph"
app:startDestination="#id/profileFragment">
<fragment
android:id="#+id/profileFragment"
android:name="lu.thebiggame.fragments.profile.ProfileFragment"
android:label="profile_fragment"
tools:layout="#layout/profile_fragment" >
<action
android:id="#+id/profileToResults"
app:destination="#id/resultsFragment" />
<action
android:id="#+id/profileToHelp"
app:destination="#id/helpFragment" />
<action
android:id="#+id/profileToPersonal"
app:destination="#id/personalFragment" />
<action
android:id="#+id/profileToChangePassword"
app:destination="#id/changePasswordFragment" />
<action
android:id="#+id/profileToPage"
app:destination="#id/pageFragment" />
</fragment>
<fragment
android:id="#+id/resultsFragment"
android:name="lu.thebiggame.fragments.results.ResultsFragment"
android:label="results_fragment"
tools:layout="#layout/results_fragment" >
<argument
android:name="startingTab"
app:argType="integer"
android:defaultValue="0" />
<deepLink
android:id="#+id/resultsFragmentDeepLink"
android:autoVerify="true"
app:uri="app://profile/results-fragment" />
<action
android:id="#+id/resultsToClaim"
app:destination="#id/claimFragmentResults" />
</fragment>
<fragment
android:id="#+id/helpFragment"
android:name="lu.thebiggame.fragments.help.HelpFragment"
android:label="help_fragment"
tools:layout="#layout/help_fragment" >
<action
android:id="#+id/helpToPage"
app:destination="#id/pageFragment" />
<action
android:id="#+id/helpToContact"
app:destination="#id/contactUsFragment" />
<action
android:id="#+id/helpToFaq"
app:destination="#id/faqFragment" />
</fragment>
<fragment
android:id="#+id/personalFragment"
android:name="lu.thebiggame.fragments.personal.PersonalFragment"
android:label="personal_fragment"
tools:layout="#layout/personal_fragment" />
<fragment
android:id="#+id/changePasswordFragment"
android:name="lu.thebiggame.fragments.changepassword.ChangePasswordFragment"
android:label="change_password_fragment"
tools:layout="#layout/change_password_fragment" />
<fragment
android:id="#+id/pageFragment"
android:name="lu.thebiggame.fragments.page.PageFragment"
android:label="page_fragment"
tools:layout="#layout/page_fragment" />
<fragment
android:id="#+id/contactUsFragment"
android:name="lu.thebiggame.fragments.contactus.ContactUsFragment"
android:label="contact_us_fragment"
tools:layout="#layout/contact_us_fragment" />
<fragment
android:id="#+id/faqFragment"
android:name="lu.thebiggame.fragments.faqfragment.FaqFragment"
android:label="faq_fragment"
tools:layout="#layout/faq_fragment" />
<fragment
android:id="#+id/claimFragmentResults"
tools:layout="#layout/claim_fragment"
android:name="lu.thebiggame.fragments.claim.ClaimFragment"
android:label="ClaimFragment" />
</navigation>
Initializing bottom navigation:
private fun setupBottomNavigationBar() {
activityMainBottomNav.itemIconTintList = null
val navGraphIds = listOf(
R.navigation.home_nav_graph,
R.navigation.games_nav_graph,
R.navigation.profile_nav_graph
)
val controller = activityMainBottomNav.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = supportFragmentManager,
containerId = R.id.nav_host_container,
intent = intent
)
currentNavController = controller
}
As nobody bothered to answer me, here is what I did. All the fragments that can appear in all three of my navigation graphs I moved to another graph and named it a shared graph. Furthemore, in order to navigate to this graph I created standard actions to it, but before navigating I made sure to change starting position of shared graph.
fun navigateToNestedGraph(navDir: NavDirections, destination: Int, navOps: NavOptions? = null){
val view = (this as Fragment).requireView()
val navController = Navigation.findNavController(view)
val graph = navController.graph.findNode(R.id.shared_nav_graph)
if (graph is NavGraph){
graph.startDestination = destination
navController.navigate(navDir, navOps)
}
}
This is a function from a listener that my Fragments implement. That's it.
I have a problem switching between fragments using my bottom navigation view.it loads first and i can switch between the fragments for the first time but if a fragment was already loaded and try to navigate back to it. My app crashes showing an error i listed below.
Here is my code
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener{
when (it.itemId) {
R.id.vegetables -> {
showFragment(VegetablesFragment(),VegetablesFragment().javaClass.simpleName)return#OnNavigationItemSelectedListener true
}
R.id.fruits -> {
showFragment(FruitsFragment(),FruitsFragment().javaClass.simpleName)
return#OnNavigationItemSelectedListener true
}
R.id.grocery -> {
showFragment(GroceryFragment(),GroceryFragment().javaClass.simpleName)
return#OnNavigationItemSelectedListener true
}
else -> return#OnNavigationItemSelectedListener false
}
}
private fun showFragment(fragment : Fragment ,fragmentName :String) {
val transaction = manager.beginTransaction()
val currentFragment = manager.primaryNavigationFragment
if (currentFragment != null) {
transaction.hide(currentFragment)
}
val fragmentTemp = manager.findFragmentByTag(fragmentName)
if (fragmentTemp == null){
transaction.add(R.id.fragmentHolder,fragment,fragmentName)
Log.d("ac1001","case 2")
} else {
Log.d("ac1001","case 1")
transaction.show(fragment)
}
transaction.setPrimaryNavigationFragment(fragment)
transaction.setReorderingAllowed(true)
transaction.commitNowAllowingStateLoss()
}
Error:
java.lang.IllegalArgumentException: Fragment VegetablesFragment{d4a075d (f9739b50-c0fc-47c1-80d1-dc413ffd5a09)} is not an active fragment of FragmentManager FragmentManager{5b1a8d2 in HostCallbacks{2810da3}}
I tried searching everywhere but couldn't find an answer.
The error is occuring on my transaction.show(..)
Thanks in advance.
Try with this code. change your showFragment function to ->
fun showFragment(fragment: Fragment ,fragmentName :String) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragmentHolder, fragment)
transaction.addToBackStack(fragmentName)
transaction.commit()
}
Hope this will help you.
Fixed it by changing my code to:
private fun showFragment(fragment : Fragment ,fragmentName :String) {
val transaction = manager.beginTransaction()
val currentFragment = manager.primaryNavigationFragment
if (currentFragment != null) {
transaction.hide(currentFragment)
}
val fragmentTemp = manager.findFragmentByTag(fragmentName)
if (fragmentTemp == null){
transaction.add(R.id.fragmentHolder,fragment,fragmentName)
} else {
transaction.show(fragmentTemp)
}
transaction.setPrimaryNavigationFragment(fragmentTemp)
transaction.setReorderingAllowed(true)
transaction.commitNowAllowingStateLoss()
}
I have set of Fragments navigates inside activity. While I called findFragmentByTag() the fragments onCreateView() and onViewCreated() are called again and the data is reset to normal. how to prevent the recreation of fragment?
You can have look on the code of the advanced navigation in android samples
fun BottomNavigationView.setupWithNavController(
navGraphIds: List<Int>,
fragmentManager: FragmentManager,
containerId: Int,
intent: Intent): LiveData<NavController> {
// Map of tags
val graphIdToTagMap = SparseArray<String>()
// Result. Mutable live data with the selected controlled
val selectedNavController = MutableLiveData<NavController>()
var firstFragmentGraphId = 0
// First create a NavHostFragment for each NavGraph ID
navGraphIds.forEachIndexed { index, navGraphId ->
val fragmentTag = getFragmentTag(index)
// Find or create the Navigation host fragment
val navHostFragment = obtainNavHostFragment(
fragmentManager,
fragmentTag,
navGraphId,
containerId
)
// Obtain its id
val graphId = navHostFragment.navController.graph.id
if (index == 0) {
firstFragmentGraphId = graphId
}
// Save to the map
graphIdToTagMap[graphId] = fragmentTag
// Attach or detach nav host fragment depending on whether it's the selected item.
if (this.selectedItemId == graphId) {
// Update livedata with the selected graph
selectedNavController.value = navHostFragment.navController
attachNavHostFragment(fragmentManager, navHostFragment, index == 0)
} else {
detachNavHostFragment(fragmentManager, navHostFragment)
}
}
// Now connect selecting an item with swapping Fragments
var selectedItemTag = graphIdToTagMap[this.selectedItemId]
val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId]
var isOnFirstFragment = selectedItemTag == firstFragmentTag
// When a navigation item is selected
setOnNavigationItemSelectedListener { item ->
// Don't do anything if the state is state has already been saved.
if (fragmentManager.isStateSaved) {
false
} else {
val newlySelectedItemTag = graphIdToTagMap[item.itemId]
if (selectedItemTag != newlySelectedItemTag) {
// Pop everything above the first fragment (the "fixed start destination")
fragmentManager.popBackStack(firstFragmentTag,
FragmentManager.POP_BACK_STACK_INCLUSIVE)
val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag)
as NavHostFragment
// Exclude the first fragment tag because it's always in the back stack.
if (firstFragmentTag != newlySelectedItemTag) {
// Commit a transaction that cleans the back stack and adds the first fragment
// to it, creating the fixed started destination.
fragmentManager.beginTransaction()
.attach(selectedFragment)
.setPrimaryNavigationFragment(selectedFragment)
.apply {
// Detach all other Fragments
graphIdToTagMap.forEach { _, fragmentTagIter ->
if (fragmentTagIter != newlySelectedItemTag) {
detach(fragmentManager.findFragmentByTag(firstFragmentTag)!!)
}
}
}
.addToBackStack(firstFragmentTag)
.setCustomAnimations(
R.anim.nav_default_enter_anim,
R.anim.nav_default_exit_anim,
R.anim.nav_default_pop_enter_anim,
R.anim.nav_default_pop_exit_anim)
.setReorderingAllowed(true)
.commit()
}
selectedItemTag = newlySelectedItemTag
isOnFirstFragment = selectedItemTag == firstFragmentTag
selectedNavController.value = selectedFragment.navController
true
} else {
false
}
}
}
// Optional: on item reselected, pop back stack to the destination of the graph
setupItemReselected(graphIdToTagMap, fragmentManager)
// Handle deep link
setupDeepLinks(navGraphIds, fragmentManager, containerId, intent)
// Finally, ensure that we update our BottomNavigationView when the back stack changes
fragmentManager.addOnBackStackChangedListener {
if (!isOnFirstFragment && !fragmentManager.isOnBackStack(firstFragmentTag)) {
this.selectedItemId = firstFragmentGraphId
}
// Reset the graph if the currentDestination is not valid (happens when the back
// stack is popped after using the back button).
selectedNavController.value?.let { controller ->
if (controller.currentDestination == null) {
controller.navigate(controller.graph.id)
}
}
}
return selectedNavController
}
this example code you can find the full code here
https://github.com/android/architecture-components-samples/tree/master/NavigationAdvancedSample