Navigatoin Graph issue when add activity - android

I am using Navigation Android component with navigation drawer, its working fine our code :
private void setupNavMenu() {
NavHeaderMainBinding navHeaderMainBinding = DataBindingUtil.inflate(getLayoutInflater(),
R.layout.nav_header_main, mActivityMainBinding.navigationView, false);
mActivityMainBinding.navigationView.addHeaderView(navHeaderMainBinding.getRoot());
navHeaderMainBinding.setViewModel(mMainViewModel);
addNavigationItem();
NavigationUI.setupActionBarWithNavController(this, navController, mActivityMainBinding.drawerView);
mNavigationView.setNavigationItemSelectedListener(
item -> {
mDrawer.closeDrawer(GravityCompat.START);
return true;
});
NavigationUI.setupWithNavController(mNavigationView, navController);
}
and this is our navigation item:
private void addNavigationItem() {
final Menu menu = mNavigationView.getMenu();
menu.add(R.id.group, R.id.test1Fragment, Menu.NONE, "test1");
menu.add(R.id.group, R.id.test2Fragment Menu.NONE, "test2");
menu.add(R.id.group, R.id.testActivity3 Menu.NONE, "test3");
}
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/home_fragment"
app:startDestination="#id/test1Fragment">
<fragment
android:id="#+id/test1Fragment"
android:name="com.test.Test1"
android:label="FragmentOne">
<action
android:id="#+id/action_test1"
app:destination="#id/test2Fragment" />
</fragment>
<fragment
android:id="#+id/test2Fragment"
android:name="com.test.Test2"
android:label="FragmentThree" >
<action
android:id="#+id/action_test2"
/>
</fragment>
<activity
android:id="#+id/testActivity3"
android:name="com.test.TestActivity"
android:label="Act"
tools:layout="#layout/activity_test"
></activity>
</navigation>
everything is working fine.Now issue is that when i click on second tag in navigation drawer and from the second fragment again open drawer and click on third tab which is Activity. then on back press stack not working properly,fragment test1 and test2 overlapped each other.How could i resolved this issue? i think backstack not working fine if i add Activity inside navigation graph.

Related

Navigation Drawer Activity's menu items are not clickable

I am trying to create a new activity with drawer layout. To do this, I used Android Studio's default code generator: File -> New -> Activity -> Navigation Drawer Activity. It created a bunch of files with fragments, drawer, and (jetpack) navigation support and their corresponding resources such as navigation file and layout files. I tried to run the new activity and it installed successfully. The problem is, my navigation drawer is not working. The menu items in my drawer do not trigger any change in host navigation fragment.
I've been stuck for a day already and have tried many solutions already and still, my menu items won't let me navigate to another destination.
Here is my resulting MainActivity.java:
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
private ActivityMainBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appBarMain.toolbar);
DrawerLayout drawer = binding.drawerLayout;
NavigationView navigationView = binding.navView;
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
.setOpenableLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
return NavigationUI.onNavDestinationSelected(
item,
Navigation.findNavController(this, R.id.nav_host_fragment_content_main)) ||
super.onOptionsItemSelected(item);
}
}
The overridden onOptionsItemSelected() function is from Android's codelab.
Here is my navigation file:
<?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/mobile_navigation"
app:startDestination="#+id/nav_home">
<fragment
android:id="#+id/nav_home"
android:name="com.bicolexpress.delivery.ui.main.ui.home.HomeFragment"
android:label="#string/menu_home"
tools:layout="#layout/fragment_home" />
<fragment
android:id="#+id/nav_gallery"
android:name="com.bicolexpress.delivery.ui.main.ui.gallery.GalleryFragment"
android:label="#string/menu_gallery"
tools:layout="#layout/fragment_gallery" />
<fragment
android:id="#+id/nav_slideshow"
android:name="com.bicolexpress.delivery.ui.main.ui.slideshow.SlideshowFragment"
android:label="#string/menu_slideshow"
tools:layout="#layout/fragment_slideshow" />
</navigation>
Based on the codelab link above:
If NavigationUI finds a menu item with the same ID as a destination on
the current graph, it configures the menu item to navigate to that
destination.
This is true for the generated menu items and destination IDs. But still, does not work. Can anyone point me to what I missed? I desperately need your help.
Android Studio Version: Electric Eel | 2022.1.1
So I tried to copy the layout from codelab. And guess what, the click listeners worked!
I noticed that in codelab's layout, the NavigationView was added into the DrawerLayout as the last child. So I modified my activity_main.xml to:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
android:id="#+id/app_bar_main"
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>

Android Navigation Component: back button pressed multiple times before it closes the app

I have a navigation graph with 4 fragments. Each fragment is a stand-alone view: can only navigate to the next fragment, but never navigate back to the previous one.
Expected behaviour:
Pressing back button should close the app. If the fragment has a pager, then the back button should navigate back the pager until it reaches index 0, then after that should close the app.
SplashFragment: a splash screen
LanguageFragment: a view to setup language
BoardingFragment: has a pager and serves as an on-boarding flow
StartupFragment: has a pager and serves as an initial set up flow
The Problem:
All works fine from Frag1 (SplashFragment) to Frag3 (BoardingFragment). But once navigated to Frag4 (StartupFragment) and pager is at index 0, I still have to press back button 7 times before it closes the app. No crashes nor error thrown.
<?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/splash_nav_graph"
app:startDestination="#id/splash_fragment">
<fragment
android:id="#+id/splash_fragment"
android:name=".ui.fragments.SplashFragment"
android:label="fragment_splash"
tools:layout="#layout/fragment_splash" >
<action
android:id="#+id/splash_to_lang_action"
app:destination="#id/language_fragment"
app:popUpTo="#id/splash_fragment"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/language_fragment"
android:name=".ui.fragments.LanguageFragment"
android:label="fragment_language"
tools:layout="#layout/fragment_language" >
<action
android:id="#+id/lang_to_boarding_action"
app:destination="#id/boarding_fragment"
app:popUpTo="#id/splash_nav_graph"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/boarding_fragment"
android:name=".ui.fragments.BoardingFragment"
android:label="fragment_boarding"
tools:layout="#layout/fragment_boarding" >
<action
android:id="#+id/boarding_to_startup_action"
app:destination="#id/startup_fragment"
app:popUpTo="#id/splash_nav_graph"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/startup_fragment"
android:name=".ui.fragments.StartupFragment"
android:label="fragment_startup"
tools:layout="#layout/fragment_startup" />
</navigation>
In SplashFragment:
// navigate after an action
navController.navigate(
R.id.splash_to_lang_action, null, null,
FragmentNavigatorExtras(binding.logo to binding.logo.transitionName)
)
In LanguageFragment:
// navigate after an action
navController.navigate(R.id.lang_to_boarding_action)
In BoardingFragment:
// navigate after an action
navController.navigate(R.id.boarding_to_startup_action)
// manage back-press for pager
activity?.onBackPressedDispatcher?.addCallback {
if (binding.uspPager.currentItem != 0) binding.uspPager.currentItem--
else {
isEnabled = false
activity?.onBackPressed()
}
}
In StartupFragment:
// manage back-press for pager
activity?.onBackPressedDispatcher?.addCallback {
if (binding.uspPager.currentItem != 0) binding.uspPager.currentItem--
else {
isEnabled = false
activity?.onBackPressed()
}
}
I appreciate any help to the max. Thanks in advance.

how to make animation transition between fragments in navigation by drawer in android

I have a drawer in my app and I switch fragments by navigation. I would like to have animation transition when I click on the button in the drawer. I know how to do it with regular button but I do not konw how to do it with navigation drawer Thank you.
this is my main Activity
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_food_text_analysis,
R.id.nav_recipe_analysis
), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
this is my navigation 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/mobile_navigation"
app:startDestination="#id/nav_food_text_analysis">
<fragment
android:id="#+id/nav_food_text_analysis"
android:name="com.example.nutritionfacts.ui.foodTextAnalysis.FoodAnalysisFragment"
android:label="Food analysis"
tools:layout="#layout/fragment_food_text_analysis" >
<action
android:id="#+id/action_nav_food_text_analysis_to_nav_recipe_analysis"
app:destination="#id/nav_recipe_analysis"
app:enterAnim="#anim/enter_from_right"
app:exitAnim="#anim/exit_to_right"
app:popEnterAnim="#anim/enter_from_right"
app:popExitAnim="#anim/exit_to_right" />
</fragment>
<fragment
android:id="#+id/nav_recipe_analysis"
android:name="com.example.nutritionfacts.ui.recipeAnalysis.RecipeAnalysisFragment"
android:label="Recipe analysis"
tools:layout="#layout/fragment_recipe_analysis" >
<action
android:id="#+id/action_nav_recipe_analysis_to_nav_food_text_analysis2"
app:destination="#id/nav_food_text_analysis"
app:enterAnim="#anim/enter_from_right"
app:exitAnim="#anim/exit_to_right"
app:popEnterAnim="#anim/enter_from_right"
app:popExitAnim="#anim/exit_to_right" />
</fragment>
</navigation>
I was just working on this and have a solution that listens for the navigation drawer clicks and reacts in the same way you would with a button.
I am using a single activity with several fragments. Make sure to set up the navigtaion graph for your fragments, then call the correct FragmentDirections action by using the setNavigationItemSelectedListener in the Main Activity.
In my example, the settingsFragment will be loaded with an animation but the aboutFragment will not since it doesn't call a Directions.action function.
MainActivity (inside onCreate function)
/** Handle clicks in Nav Drawer **/
val navigationView = findViewById<NavigationView>(R.id.navView)
navigationView.setNavigationItemSelectedListener { menuItem ->
Timber.d("Nav Drawer Item Clicked: %s", menuItem.title)
when (menuItem.itemId) {
R.id.settingsFragment -> {
navController.navigate(
RecipeListFragmentDirections
.actionRecipeListToSettingsFragment()
)
}
R.id.aboutFragment -> {
navController.navigate(R.id.aboutFragment)
}
R.id.refreshRecipes -> {
Timber.i("TODO: Implement repository refresh method call")
}
}
true
}
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/navigation"
app:startDestination="#id/recipeList">
<fragment
android:id="#+id/recipeList"
android:name="com.jumptuck.recipebrowser2.recipelist.RecipeListFragment"
tools:layout="#layout/fragment_recipe_list">
<action
android:id="#+id/action_recipeList_to_singleRecipeFragment"
app:destination="#id/singleRecipeFragment"
app:enterAnim="#anim/slide_in_right"
app:exitAnim="#anim/slide_out_right"
app:popEnterAnim="#anim/slide_in_left"
app:popExitAnim="#anim/slide_out_left" />
<action
android:id="#+id/action_recipeList_to_aboutFragment"
app:destination="#id/aboutFragment"
app:enterAnim="#anim/slide_in_left"
app:exitAnim="#anim/slide_out_left"
app:popEnterAnim="#anim/slide_in_right"
app:popExitAnim="#anim/slide_out_right" />
<action
android:id="#+id/action_recipeList_to_settingsFragment"
app:destination="#id/settingsFragment"
app:enterAnim="#anim/slide_in_right"
app:exitAnim="#anim/slide_out_right"
app:popEnterAnim="#anim/slide_in_left"
app:popExitAnim="#anim/slide_out_left" />
</fragment>
One of the reasons I've used this approach is because I want to start a service from the refreshRecipes menu item rather than causing a navigation and this intercepts the click. One of the drawbacks is that the navigation bar items themselves don't show an animation when clicked (however I think this can be fixed).

Handle onBackPressed in Android Navigation Component

I have implemented navigation Drawer with Navigation Components in Android. I have 5 fragments that I want to go back to my HomeFragment when I click on back pressed. For the moment they stay onBackStack and do not go to my desired fragment but go to whatever fragment was first.
This is my nav_graph :
<?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"
app:startDestination="#id/setupFragment"
android:id="#+id/treasure_nav"
android:label="Pick a country">
<fragment android:id="#+id/homeFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.home.HomeFragment"
android:label="Home"
tools:layout="#layout/fragment_home">
<action android:id="#+id/action_home_fragment_to_namesFragment2"
app:popUpTo="#id/homeFragment"
app:destination="#id/namesFragment"/>
<action android:id="#+id/action_home_fragment_to_quranFragment"
app:popUpTo="#id/homeFragment"
app:destination="#id/quranFragment"/>
<action android:id="#+id/action_homeFragment_to_tasbeehFragment"
app:popUpTo="#id/homeFragment"
app:destination="#id/tasbeehFragment"/>
<action android:id="#+id/action_homeFragment_to_galleryFragment"
app:popUpTo="#id/homeFragment"
app:destination="#id/galleryFragment"/>
<action android:id="#+id/action_homeFragment_to_newsFragment"
app:popUpTo="#id/homeFragment"
app:destination="#id/newsFragment"/>
<action android:id="#+id/action_homeFragment_to_settingsFragment"
app:popUpTo="#id/homeFragment"
app:destination="#id/settingsFragment"/>
</fragment>
<fragment
android:id="#+id/namesFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.names.NamesFragment"
android:label="Names of Allah"
tools:layout="#layout/fragment_names"/>
<fragment
android:id="#+id/quranFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.quran.QuranFragment"
android:label="Quran"
tools:layout="#layout/fragment_quran"/>
<fragment android:id="#+id/tasbeehFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.tasbeeh.TasbeehFragment"
android:label="Tasbeeh"
tools:layout="#layout/fragment_tasbeeh"/>
<fragment android:id="#+id/galleryFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.gallery.GalleryFragment"
android:label="Gallery"
tools:layout="#layout/fragment_gallery"/>
<fragment android:id="#+id/newsFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.news.NewsFragment"
android:label="News"
tools:layout="#layout/fragment_news"/>
<fragment android:id="#+id/settingsFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.settings.SettingsFragment"
android:label="Settings"
tools:layout="#layout/fragment_settings"/>
<fragment android:id="#+id/setupFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.setup.SetupFragment"
android:label="Pick country"
tools:layout="#layout/fragment_setup">
<action android:id="#+id/action_setupFragment_to_homeFragment3"
app:destination="#+id/homeFragment"
app:launchSingleTop="true"
app:popUpTo="#+id/treasure_nav"
app:popUpToInclusive="true"/>
</fragment>
</navigation>
And this is my onBackPressed in my MainActivity (and the only one) :
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
Edit: When i remove the super.onBackPressed() and replace it with :
findNavController(R.id.nav_host_fragment).popBackStack(R.id.homeFragment, false) I achieve what I want. The only problem is that when I am in the homeFragment I want to end the app but I can't.
If my understanding is correct, you want to go back to HomeFragment wherever you are in the navigation flow. For this case you could try registering OnBackPressedCallback on your Fragments via addOnBackPressedCallback, and call popBackStack to navigate to your HomeFragment. Try adding this to Fragments' onViewCreated that need to go back to HomeFragment on backpress:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
navController = Navigation.findNavController(view);
requireActivity().addOnBackPressedCallback(getViewLifecycleOwner(), () -> {
navController.popBackStack(R.id.homeFragment, false);
});
return true;
});
If you want to close app when press back in HomeFragment, it's just specified these attributes of the last action that navigates you to this destination:
app:popUpToInclusive to true
app:popUpTo to of the last fragment(SetupFragment) that navigates you here(HomeFragment)
It means change your code like this:
<fragment android:id="#+id/setupFragment"
android:name="com.stavro_xhardha.pockettreasure.ui.setup.SetupFragment"
android:label="Pick country"
tools:layout="#layout/fragment_setup">
<action android:id="#+id/action_setupFragment_to_homeFragment3"
app:destination="#+id/homeFragment"
app:launchSingleTop="true"
app:popUpTo="#+id/setupFragment" // this line changes
app:popUpToInclusive="true" /> // and this requires too
</fragment>

Is it possible to set startDestination conditionally using Android Navigation Architecture Component(Android Jetpack)?

I am using Navigation from Android Jetpack to navigate between screens.
Now I want to set startDestination dynamically.
I have an Activity named MainActivity
And two Fragments, FragmentA & FragmentB.
var isAllSetUp : Boolean = // It is dynamic and I’m getting this from Preferences.
If(isAllSetUp)
{
// show FragmentA
}
else
{
//show FragmentB
}
I want to set above flow using Navigation Architecture Component. Currently I have used startDestionation as below but it’s not fulfilling my requirement.
<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/lrf_navigation"
app:startDestination="#id/fragmentA">
<fragment
android:id="#+id/fragmentA"
android:name="com.mindinventory.FragmentA"
android:label="fragment_a"
tools:layout="#layout/fragment_a" />
</navigation>
Is it possible to set startDestination conditionally using Android Navigation Architecture Component?
Finally, I got a solution to my query...
Put below code in onCreate() method of Activity.
Kotlin code
val navHostFragment = (supportFragmentManager.findFragmentById(R.id.home_nav_fragment) as NavHostFragment)
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.nav_main)
//graph.addArgument("argument", NavArgument)
graph.setStartDestination(R.id.fragment1)
//or
//graph.setStartDestination(R.id.fragment2)
navHostFragment.navController.graph = graph
Java code
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.home_nav_fragment); // Hostfragment
NavInflater inflater = navHostFragment.getNavController().getNavInflater();
NavGraph graph = inflater.inflate(R.navigation.nav_main);
//graph.addArgument("argument", NavArgument)
graph.setStartDestination(R.id.fragment1);
navHostFragment.getNavController().setGraph(graph);
navHostFragment.getNavController().getGraph().setDefaultArguments(getIntent().getExtras());
NavigationView navigationView = findViewById(R.id.navigationView);
NavigationUI.setupWithNavController(navigationView, navHostFragment.getNavController());
Additional Info
As #artnest suggested, remove the app:navGraph attribute from the layout. It would look something like this after removal
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/home_nav_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true" />
</FrameLayout>
In the case of a fragment tag used instead of FragmentContainerView, the above changes remain the same
Some of the APIs have changed, are unavailable or are not necessary since Akash's answer. It's a bit simpler now.
MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NavHostFragment navHost = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_main_nav_host);
NavController navController = navHost.getNavController();
NavInflater navInflater = navController.getNavInflater();
NavGraph graph = navInflater.inflate(R.navigation.navigation_main);
if (false) {
graph.setStartDestination(R.id.oneFragment);
} else {
graph.setStartDestination(R.id.twoFragment);
}
navController.setGraph(graph);
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<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">
<!-- Following line omitted inside <fragment> -->
<!-- app:navGraph="#navigation/navigation_main" -->
<fragment
android:id="#+id/fragment_main_nav_host"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
navigation_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- Following line omitted inside <navigation>-->
<!-- app:startDestination="#id/oneFragment" -->
<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/navigation_main"
>
<fragment
android:id="#+id/oneFragment"
android:name="com.apponymous.apponymous.OneFragment"
android:label="fragment_one"
tools:layout="#layout/fragment_one"/>
<fragment
android:id="#+id/twoFragment"
android:name="com.apponymous.apponymous.TwoFragment"
android:label="fragment_two"
tools:layout="#layout/fragment_two"/>
</navigation>
This can be done with navigation action. Because fragmentA is your start destination, so define an action in fragmentA.
Note these two fields:
app:popUpToInclusive="true" app:popUpTo="#id/fragmentA"
<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/lrf_navigation"
app:startDestination="#id/fragmentA">
<fragment
android:id="#+id/fragmentA"
android:name="com.mindinventory.FragmentA"
android:label="fragment_a"
tools:layout="#layout/fragment_a">
<action android:id="#+id/action_a_to_b"
app:destination="#id/fragmentB"
app:popUpToInclusive="true"
app:popUpTo="#id/fragmentA"/>
<fragment>
<fragment
android:id="#+id/fragmentB"
android:name="com.mindinventory.FragmentB"
android:label="fragment_b"
tools:layout="#layout/fragment_b"/>
</navigation>
When your MainActivity started, just do the navigation with action id, it will remove fragmentA in the stack, and jump to fragmentB. Seemingly, fragmentB is your start destination.
if(!isAllSetUp)
{
// FragmentB
navController.navigate(R.id.action_a_to_b)
}
this is not an answer but Just a replication of #Akash Patel answer in more clean and clear way
// in your MainActivity
navController = findNavController(R.id.nav_host_fragment)
val graph = navController.navInflater.inflate(R.navigation.nav_graph)
if (Authentication.checkUserLoggedIn()) {
graph.startDestination = R.id.homeFragment
} else {
graph.startDestination = R.id.loginFragment
}
navController.graph = graph
You can set your starting destination programmatically, however, most of the time your starting logic will consult some remote endpoint. If you don't show anything on screen your UI will look bad.
What I do is always show a Splash screen. It will determine which is the next Screen to Show.
For instance, in the picture above you can ask in the Splash Screen State if there is a saved LoginToken. In case it's empty then you navigate to the Login Screen.
Once the Login Screen is done, then you analyze the result save the Token and navigate to your Next Fragment Home Screen.
When the Back Button is Pressed in the Home Screen, you will send back a Result message to the Splash Screen that indicates it to finish the App.
To pop 1 Fragment back and navigate to another you can use the following code:
val nextDestination = if (loginSuccess) {
R.id.action_Dashboard
} else {
R.id.action_NotAuthorized
}
val options = NavOptions.Builder()
.setPopUpTo(R.id.loginParentFragment, true)
.build()
findNavController().navigate(nextDestination, null, options)

Categories

Resources