Android Jetpack Navigation, BottomNavigationView with Youtube or Instagram like proper back navigation (fragment back stack)?
Solution 1
With the version 2.4.0 of the navigation package, it is finally officially supported!
https://developer.android.com/jetpack/androidx/releases/navigation#version_240_2
Not only that: after uploading the navigation library to this version, this feature is the default behaviour. And as a side note, now this default behaviour includes that fragments are not recreated when navigating among them, that seemed to be something quite requested.
Solution 2
You don't really need a ViewPager
to work with BottomNavigation
and the new Navigation architecture component. I have been working in a sample app that uses exactly the two, see here.
The basic concept is this, you have the main activity that will host the BottomNavigationView
and that is the Navigation host for your navigation graph, this is how the xml for it look like:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainActivity">
<fragment
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@+id/navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/navigation" />
</android.support.constraint.ConstraintLayout>
The navigation Menu (tabs menu) for the BottomNavigationView
looks like this:
navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_home"
android:icon="@drawable/ic_home"
android:title="@string/title_home" />
<item
android:id="@+id/navigation_people"
android:icon="@drawable/ic_group"
android:title="@string/title_people" />
<item
android:id="@+id/navigation_organization"
android:icon="@drawable/ic_organization"
android:title="@string/title_organization" />
<item
android:id="@+id/navigation_business"
android:icon="@drawable/ic_business"
android:title="@string/title_business" />
<item
android:id="@+id/navigation_tasks"
android:icon="@drawable/ic_dashboard"
android:title="@string/title_tasks" />
</menu>
All of this is just the BottomNavigationView
setup. Now to make it work with the Navigation Arch Component you need to go into the navigation graph editor, add all your fragment destinations (in my case I have 5 of them, one for each tab) and set the id of the destination with the same name as the one in the navigation.xml
file:
This will tell android to make a link between the tab and the fragment, now every time the user clicks the "Home" tab android will take care of loading up the correct fragment.
There is also one piece of kotlin code that needs to be added to your NavHost (the main activity) to wire things up with the BottomNavigationView
:
You need to add in your onCreate:
bottomNavigation.setupWithNavController(Navigation.findNavController(this, R.id.my_nav_host_fragment))
This tells android to do the wiring between the Navigation architecture component and the BottomNavigationView. See more in the docs.
To get the same beahvior you have when you use youtube, just add this:
navigation.setOnNavigationItemSelectedListener {item ->
onNavDestinationSelected(item, Navigation.findNavController(this, R.id.my_nav_host_fragment))
}
This will make destinations go into the backstack so when you hit the back button, the last visited destination will be popped up.
Solution 3
You have to set host navigation like below xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary" />
<fragment
android:id="@+id/navigation_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_navigation_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemIconTint="@drawable/color_state_list"
app:itemTextColor="@drawable/color_state_list"
app:menu="@menu/menu_bottom_navigation" />
</LinearLayout>
Setup With Navigation Controller :
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_host_fragment);
NavigationUI.setupWithNavController(bottomNavigationView, navHostFragment.getNavController());
menu_bottom_navigation.xml :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@id/tab1" // Id of navigation graph
android:icon="@mipmap/ic_launcher"
android:title="@string/tab1" />
<item
android:id="@id/tab2" // Id of navigation graph
android:icon="@mipmap/ic_launcher"
android:title="@string/tab2" />
<item
android:id="@id/tab3" // Id of navigation graph
android:icon="@mipmap/ic_launcher"
android:title="@string/tab3" />
</menu>
nav_graph.xml :
<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/nav_graph"
app:startDestination="@id/tab1">
<fragment
android:id="@+id/tab1"
android:name="com.navigationsample.Tab1Fragment"
android:label="@string/tab1"
tools:layout="@layout/fragment_tab_1" />
<fragment
android:id="@+id/tab2"
android:name="com.navigationsample.Tab2Fragment"
android:label="@string/tab2"
tools:layout="@layout/fragment_tab_2"/>
<fragment
android:id="@+id/tab3"
android:name="com.simform.navigationsample.Tab3Fragment"
android:label="@string/tab3"
tools:layout="@layout/fragment_tab_3"/>
</navigation>
By setting up the same id of "nav_graph" to "menu_bottom_navigation" will handle the click of bottom navigation.
You can handle back action using popUpTo
property in action
tag.
Solution 4
First, let me clarify how Youtube and Instagram handles fragment navigation.
- When the user is on a detail fragment, back or up pop the stack once, with the state properly restaured. A second click on the already selected bottom bar item pop all the stack to the root, refreshing it
- When the user is on a root fragment, back goes to the last menu selected on the bottom bar, displaying the last detail fragment, with the state properly restaured (JetPack doesn't)
- When the user is on the start destination fragment, back finishes activity
None of the other answers above solve all this problems using the jetpack navigation.
JetPack navigation has no standard way to do this, the way that I found more simple is to dividing the navigation xml graph into one for each bottom navigation item, handling the back stack between the navigation items myself using the activity FragmentManager and use the JetPack NavController to handle the internal navigation between root and detail fragments (its implementation uses the childFragmentManager stack).
Suppose you have in your navigation
folder this 3 xmls:
res/navigation/
navigation_feed.xml
navigation_explore.xml
navigation_profile.xml
Have your destinationIds inside the navigation xmls the same of your bottomNavigationBar menu ids. Also, to each xml set the app:startDestination
to the fragment that you want as the root of the navigation item.
Create a class BottomNavController.kt
:
class BottomNavController(
val context: Context,
@IdRes val containerId: Int,
@IdRes val appStartDestinationId: Int
) {
private val navigationBackStack = BackStack.of(appStartDestinationId)
lateinit var activity: Activity
lateinit var fragmentManager: FragmentManager
private var listener: OnNavigationItemChanged? = null
private var navGraphProvider: NavGraphProvider? = null
interface OnNavigationItemChanged {
fun onItemChanged(itemId: Int)
}
interface NavGraphProvider {
@NavigationRes
fun getNavGraphId(itemId: Int): Int
}
init {
var ctx = context
while (ctx is ContextWrapper) {
if (ctx is Activity) {
activity = ctx
fragmentManager = (activity as FragmentActivity).supportFragmentManager
break
}
ctx = ctx.baseContext
}
}
fun setOnItemNavigationChanged(listener: (itemId: Int) -> Unit) {
this.listener = object : OnNavigationItemChanged {
override fun onItemChanged(itemId: Int) {
listener.invoke(itemId)
}
}
}
fun setNavGraphProvider(provider: NavGraphProvider) {
navGraphProvider = provider
}
fun onNavigationItemReselected(item: MenuItem) {
// If the user press a second time the navigation button, we pop the back stack to the root
activity.findNavController(containerId).popBackStack(item.itemId, false)
}
fun onNavigationItemSelected(itemId: Int = navigationBackStack.last()): Boolean {
// Replace fragment representing a navigation item
val fragment = fragmentManager.findFragmentByTag(itemId.toString())
?: NavHostFragment.create(navGraphProvider?.getNavGraphId(itemId)
?: throw RuntimeException("You need to set up a NavGraphProvider with " +
"BottomNavController#setNavGraphProvider")
)
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
)
.replace(containerId, fragment, itemId.toString())
.addToBackStack(null)
.commit()
// Add to back stack
navigationBackStack.moveLast(itemId)
listener?.onItemChanged(itemId)
return true
}
fun onBackPressed() {
val childFragmentManager = fragmentManager.findFragmentById(containerId)!!
.childFragmentManager
when {
// We should always try to go back on the child fragment manager stack before going to
// the navigation stack. It's important to use the child fragment manager instead of the
// NavController because if the user change tabs super fast commit of the
// supportFragmentManager may mess up with the NavController child fragment manager back
// stack
childFragmentManager.popBackStackImmediate() -> {
}
// Fragment back stack is empty so try to go back on the navigation stack
navigationBackStack.size > 1 -> {
// Remove last item from back stack
navigationBackStack.removeLast()
// Update the container with new fragment
onNavigationItemSelected()
}
// If the stack has only one and it's not the navigation home we should
// ensure that the application always leave from startDestination
navigationBackStack.last() != appStartDestinationId -> {
navigationBackStack.removeLast()
navigationBackStack.add(0, appStartDestinationId)
onNavigationItemSelected()
}
// Navigation stack is empty, so finish the activity
else -> activity.finish()
}
}
private class BackStack : ArrayList<Int>() {
companion object {
fun of(vararg elements: Int): BackStack {
val b = BackStack()
b.addAll(elements.toTypedArray())
return b
}
}
fun removeLast() = removeAt(size - 1)
fun moveLast(item: Int) {
remove(item)
add(item)
}
}
}
// Convenience extension to set up the navigation
fun BottomNavigationView.setUpNavigation(bottomNavController: BottomNavController, onReselect: ((menuItem: MenuItem) -> Unit)? = null) {
setOnNavigationItemSelectedListener {
bottomNavController.onNavigationItemSelected(it.itemId)
}
setOnNavigationItemReselectedListener {
bottomNavController.onNavigationItemReselected(it)
onReselect?.invoke(it)
}
bottomNavController.setOnItemNavigationChanged { itemId ->
menu.findItem(itemId).isChecked = true
}
}
Do your layout main.xml
like this:
<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">
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/bottomNavigationView"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:menu="@menu/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
Use on your activity like this:
class MainActivity : AppCompatActivity(),
BottomNavController.NavGraphProvider {
private val navController by lazy(LazyThreadSafetyMode.NONE) {
Navigation.findNavController(this, R.id.container)
}
private val bottomNavController by lazy(LazyThreadSafetyMode.NONE) {
BottomNavController(this, R.id.container, R.id.navigation_feed)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
bottomNavController.setNavGraphProvider(this)
bottomNavigationView.setUpNavigation(bottomNavController)
if (savedInstanceState == null) bottomNavController
.onNavigationItemSelected()
// do your things...
}
override fun getNavGraphId(itemId: Int) = when (itemId) {
R.id.navigation_feed -> R.navigation.navigation_feed
R.id.navigation_explore -> R.navigation.navigation_explore
R.id.navigation_profile -> R.navigation.navigation_profile
else -> R.navigation.navigation_feed
}
override fun onSupportNavigateUp(): Boolean = navController
.navigateUp()
override fun onBackPressed() = bottomNavController.onBackPressed()
}
Solution 5
You can have a viewpager setup with bottom navigation view. Each fragment in the viewpager will be a container fragment, it will have child fragments with its own backstack. You can maintain backstack for each tab in viewpager this way
Related videos on Youtube
Comments
-
Bincy Baby almost 2 years
Android Jetpack Navigation, BottomNavigationView with auto fragment back stack on back button click?
What I wanted, after choosing multiple tabs one after another by user and user click on back button app must redirect to the last page he/she opened.
I achieved the same using Android ViewPager, by saving the currently selected item in an ArrayList. Is there any auto back stack after Android Jetpack Navigation Release? I want to achieve it using navigation graph
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.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:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".main.MainActivity"> <fragment android:id="@+id/my_nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="0dp" app:defaultNavHost="true" app:layout_constraintBottom_toTopOf="@+id/navigation" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/nav_graph" /> <android.support.design.widget.BottomNavigationView android:id="@+id/navigation" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="0dp" android:layout_marginEnd="0dp" android:background="?android:attr/windowBackground" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:menu="@menu/navigation" /> </android.support.constraint.ConstraintLayout>
navigation.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/navigation_home" android:icon="@drawable/ic_home" android:title="@string/title_home" /> <item android:id="@+id/navigation_people" android:icon="@drawable/ic_group" android:title="@string/title_people" /> <item android:id="@+id/navigation_organization" android:icon="@drawable/ic_organization" android:title="@string/title_organization" /> <item android:id="@+id/navigation_business" android:icon="@drawable/ic_business" android:title="@string/title_business" /> <item android:id="@+id/navigation_tasks" android:icon="@drawable/ic_dashboard" android:title="@string/title_tasks" /> </menu>
also added
bottomNavigation.setupWithNavController(Navigation.findNavController(this, R.id.my_nav_host_fragment))
I got one answer from
Levi Moreira
, as followsnavigation.setOnNavigationItemSelectedListener {item -> onNavDestinationSelected(item, Navigation.findNavController(this, R.id.my_nav_host_fragment)) }
But by doing this only happening is that last opened fragment's instance creating again.
Providing proper Back Navigation for BottomNavigationView
-
Ramki Anba almost 6 yearsHi @BincyBaby i need same thing did you get any solutions?
-
Bincy Baby almost 6 yearsnot yet got answer
-
HawkPriest over 5 yearsCommenting a bit late but upon some digging I found that the
popBackStack
is called from theNavController.navigate()
function whenNavOptions
are not null. My guess is that at the moment it is not possible to do it out of the box. A custom implementation of NavController is required that accesses themBackStack
through reflection or something like that. -
Marcus Hooper over 5 yearsIf you add a listener to the bottom nav you can override the navigation so that it will pop back stack if the stack already contains the new destination or otherwise perform the normal navigation if it doesn't.
if (!navHost.popBackStack(it.itemId, false)) navHost.navigate(it.itemId)
-
jL4 over 5 yearsA workaround for the fragment recreation problem - stackoverflow.com/a/51684125/6024687
-
hosseinAmini almost 5 yearsDid you find any proper way to achieve this?
-
Sunil Kumar almost 5 yearsmobologicplus.com/β¦ this tutorial might be help
-
KFJK over 2 yearsMy easy solution: stackoverflow.com/a/69566457/8154045
-
-
Bincy Baby almost 6 yearsI was using that way, but app starting takes too much time to first launch
-
Suhaib Roomy almost 6 yearsThen you must be doing something wrong, make sure you are not doing some heavy work in the oncreate or oncreateview of the fragments. There is no way it would take time
-
Bincy Baby almost 6 yearsI have to load contents , i don't think youtube or instagram used ViewPager
-
Suhaib Roomy almost 6 yearsIts definitely a viewpager. Just scroll on one page and try switiching tabs, its really fast and it resumes from the same state. There is no way you can achieve it by changing fragments on the same container, these are multiple fragments viewed using a viewpager
-
JamesSugrue almost 6 yearsThe secret sauce was adding the id in the nav graph. I'm using Navigation Drawer, but the principal is the same
-
Bincy Baby almost 6 yearsCan we have single instance of fragment ?
-
Levi Moreira almost 6 yearsI'm not sure, the lib is the one who takes care of instantiation, but I haven't see anywhere a place where we can configure that :/
-
Bincy Baby almost 6 yearsBut actually am not looking for this one, i want to get back the instance where we last went
-
Niroshan almost 6 yearsThis is working fine with the back-button. But if user click on bottom tabs its not restoring the previously open child-fragment of that tab(if available). It just opening the new instant of (parent) fragment every time user click on bottom tabs. So this way will lead to a confusing/ frustrating nevigation experience to the users if navigated using bottom tabs many times. Dangerous implementation
-
Suhaib Roomy almost 6 yearsthey are not using a single fragment container. Each page is maintaining its own backstack. moreover its really fast to switch between tabs. either its a viewpager or they have a custom implementation of it
-
Patrick Steiger almost 6 yearsIf back button is not working (that is, if the app is closing instead of going to the first fragment) make sure the ids are all set up correctly (I had to add some '+' in the '@id' (as in @+id) and that the NavHostFragment is setup with app:defaultNavHost=true
-
Bincy Baby almost 6 yearscan you elaborate use of popUpTo ?
-
SANAT over 5 years@BincyBaby popUpTo property helps you to return on particular fragment on back press.
-
Bincy Baby over 5 yearsBut youtube, Instagram, Saavn has different behaviour
-
Husayn Hakeem over 5 yearsTrue, there's no right or wrong way of doing it, it's just about what google supports by default (and thus recommends) and what your needs are. If these two don't align you need to work around it.
-
HawkPriest over 5 yearsMy guess is also that YouTube or Instagram do not use
ViewPager
. The restoring happens because of the backStack pop action that resumes the underlying fragment that is added in the first place not replaced -
Marty Miller over 5 yearsI thought you could only have three tabs in BottomNavigationView max. Is that not the case anymore?
-
Levi Moreira over 5 yearsThere's no max number, but material design rules state you should only have 5 tabs max
-
Allan Veloso over 5 years@SANAT but how to set up the popUpTo to the fragment imediatelly pressed before? Like, if you were in frag1 went to frag2 and then to frag3, back press should go back to frag2. If you were in frag1 and went directly to frag3, back press sould go back to frag1. The
popUpTo
seems to only let you choose one fragment to go back idependently of the user path. -
Allan Veloso over 5 yearsBut the problem is that if you are using the JetPack Navigation the backStack will be empty. Apparently JetPack is not adding nothing to the back stack when handling BottomNavigation clicks.
-
Sim about 5 yearsthis solution looks good but there are some things i noticed :
<FrameLayout />
should be aNavHostFragment
, every graph got it's own home default so doing thisif (savedInstanceState == null) bottomNavController .onNavigationItemSelected()
will trigger the fragment two times , it doesn't hold states for the fragments. -
Allan Veloso about 5 yearsThe idea of the saved instance state exactly avoided the fragment be created two times. I can't check this because I ended up extending the
NavController
, and creating a custom Navigator exclusively forNavHostFragment
s, adding it to this NavController (I calledNavHostFragmentNavController
). Then I create a graph called navigation_main.xml with the <nav-fragment> elements that represent each a bottom navigation item. The new implementations are bigger but the usage quite simple. The code still has some small bugs that I did not finish yet. I will post it when I fix them. -
Sim about 5 yearsyes i guess for now extending the
NavController
is a sane solution, till Google release the sample. -
WWJD about 5 yearsShouldn't here a destination be passed as the last parameter instead of
R.id.navigation_feed
?private val bottomNavController by lazy(LazyThreadSafetyMode.NONE) { BottomNavController(this, R.id.container, R.id.navigation_feed) }
-
Allan Veloso about 5 years@WWJD, R.id.navigation_feed is a destination. I named the graph id with the same name as it's an initial destination, so
R.navigation.navigation_feed
has aR.id.navigation_feed
destination. -
jfcogato about 5 years@AllanVeloso this works perfect for me. Great solution, I just remove the NavigationExtension.kt from the google demo, and added all your code, and works perfect. I just made some updates on the code because I'm using AHBottomNavigation, but works the same. For me this would be the real solution to make a multi stag navigation with the new navigation system.
-
jfcogato about 5 yearsSorry for the noise, I just made an improve of that code adding a "fragmentManager.addOnBackStackChangedListener" on the init of the controller, so you could add the "OnDestinationChangedListener". That way you will always know in what fragment are you, from the controller. That way you can make some updates on the Activity UI in case of need. Ping me if you need the update on the code. Thanks again for this thread! Now works awesome for me.
-
Allan Veloso about 5 years@jfcogato To keep tracking of the Destination change you can also extend MutableLiveData. The usage would be very simple:
DestinationLiveData(navController).observe(this, Observer { dest -> // do things })
. It also handles the add and remove listener methods automatically. Right now I am trying to develop a more complete library that overrides the NavController jetpack implementation with this Instagram/youtube behaviour, but I am still fixing some bugs. -
jfcogato about 5 years@AllanVeloso sure that will be another way to get it. Looks more clean-code than mine :) I will wait for you library! maybe I could update all what I did with yours. By the way you really save my day, this solution works fine! and I think that all of my project will be working with this navigation system for now and forever! :)
-
Dushyant Suthar about 5 years@AllanVeloso onNavigationItemReselected Doesn't work. I mean popBackStack always returns false. Otherwise everything works like charm.
-
Sohel S9 about 5 years@LeviMoreira Can you please provide demo link for this ?
-
Dushyant Suthar about 5 years@AllanVeloso Could you please see or help on this ?
-
Allan Veloso almost 5 years@DushyantSuthar the implementation of the android arch navigation library changed and now popBackStack() has in my opinion a quite strange behavior (according to Android Team, intended). You can try to replace the .popBackStack() for .navigate(navController.currentDestination.parent) or something similar and check if it works.
-
Farid almost 5 yearsNot preserving back stack order, back button jumps to 1st tab excluding the 2nd tab. Not only that, won't preserve fragment state, instead creates new instance on every ButtomNavigationItem click.
-
kondal almost 5 yearsI dotn want to recreate the fragment again when user switches bottom tabs how to achieve this .in the sense i don't want to make an API call again each time when user switching fragment
-
rubenwardy almost 5 yearsyou should also hide the "up" arrows on direct children of the BNV: setupActionBarWithNavController(navController, AppBarConfiguration.Builder(bottomNavigationView.menu).build())
-
Sohail Zahid over 4 years@kondal have you find any solution for not recreating fragments again and again
-
Sohail Zahid over 4 years@Farid can control to not create new instance every time on selection.
-
OK200 over 4 years@Niroshan, have you found any solution to your problem, help me if you have found
-
Niroshan over 4 years@OK200 Not an official answer! But we can overcome this by extending the default FragmentNavigator. Check out the this simple sample github.com/STAR-ZERO/navigation-keep-fragment-sample ! (Have a look at 'KeepStateNavigator' class). **Don't forget to replace the 'fragment' key word to 'keep_state_fragment'(or the keyword annotation used in your extended class ) used in your nav_graph(xml)
-
Morten Holmgaard over 4 yearsSolve the problem with recreating tabs by having this in your BaseFragment: (It should be a recommended solution but forgot where I read it)
private var previousLoadedView: View? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { if (previousLoadedView == null) { previousLoadedView = inflater.inflate(layoutId, container, false) } else { (previousLoadedView?.parent as? ViewGroup)?.removeAllViews() } return previousLoadedView }
-
Suyash Dixit over 4 years@Farid do you know solution to this? It is causing me a problem.
-
Farid over 4 years@SuyashDixit, honestly, I didn't go with this pattern but you can do the following. Create your fragments and
show/hide
them instead ofadd/replace
ing them. If this is not clear, I will post a code snippet as an answer -
Vaios about 4 years@Niroshan Basically, there is an official workaround until they fix the problem. You can find it here github.com/android/architecture-components-samples/blob/mastββer/β¦
-
Manish Karena about 4 yearsIt is working fine with normal navigation, but there is one issue while navigating using BottomNavigationView. For instance, let's say I have BottomNavigation with three tab with it's respected Fragments A, B, C. Now my navigation path is Fragment A to B(click on tab B), from B to D(it's another fragment opened on button click from B), D to E(another fragment opened on button click from D) and lastly E to C(by clicking on tab C); from there when i press back it's going to fragment E but it shows the current selected tab C(Ideally it should show tab B), Is there any way i can fix this?
-
Shalan93 about 4 yearsthis is the how-to using the navigation UI with bottom navigation view and not helping to solve this issue!
-
Sunil Chaudhary almost 4 yearsdo you have any idea about this stackoverflow.com/questions/63052712/β¦
-
Thracian almost 4 years@SunilChaudhary, yes if you check out repo for navigation components, or extension function above or in the link you can see how it works. Examples in this repo show how to do it with different ways.
-
Sunil Chaudhary almost 4 yearshave any idea can we use this on my demo stackoverflow.com/questions/63052712/β¦
-
Nouman Ch over 3 yearswhat if I press the back button? fragment will navigateUp but the bottomNavbar will not be updated.
-
RodParedes over 2 yearsOMG you are a genius. I 'been looking for my navigation to have features like this. Have you uploaded this repo to github by any chance?