Pav Sidhu
Pav Sidhu

Reputation: 6944

Android Navigation: Access NavHostFragment from same Fragment

Currently I have the following scenario: a user must sign in to use the app. This means I've used 2 nav_graphs, a main graph for everything and then a nested home graph for the views after you have signed in.

After signing in, a bottom navigation bar should appear to change tabs in the home graph.

I have the following home_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">

    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".ui.home.HomeFragment">

        <fragment
                android:id="@+id/home_nav_host_fragment"
                android:name="androidx.navigation.fragment.NavHostFragment"
                app:navGraph="@navigation/home_graph"
                app:defaultNavHost="true"/>

        <com.google.android.material.bottomnavigation.BottomNavigationView
                android:id="@+id/bottom_navigation"
                app:menu="@menu/navigation_items"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

And I want to be able to change tabs in the bottom navigation view, so I setup this logic in HomeFragement.kt using bottomNavigationView.setOnNavigationItemSelectedListener.

Unfortunetly, when I try to fetch the home_nav_host_fragment in home_fragment.xml I cannot because homeNavController = findNavController() in the fragment can only find the main_nav_host_fragment that's in the main activity.

I want findNavController() to return the home_nav_host_fragment instead but because this method only searches for parent NavControllers and not ones on the same level it cannot find the one I want.

Is there a better structure that will provide a solution to this issue? Thanks

Upvotes: 2

Views: 1164

Answers (2)

Martin Zeitler
Martin Zeitler

Reputation: 76579

Better use popUpTo combined with popUpToInclusive to create a one-way navigation action - in order to use a single one graph, instead of two disconnected graphs. This only should be applied to the first 1-2 fragments in the graph, so that eg. the back button cannot navigate back to the splash-screen or to the login-screen, because these actions do not count towards "the expected behavior".

<fragment
    android:id="@+id/splashFragment"
    android:name="com.acme.fragment.SplashFragment"
    tools:layout="@layout/fragment_splash"
    android:label="fragment_splash">

    <action
        android:id="@+id/action_splashFragment_to_loginFragment"
        app:destination="@id/loginFragment"
        app:popUpTo="@id/splashFragment"
        app:popUpToInclusive="true"/>

</fragment>

Upvotes: 0

ianhanniballake
ianhanniballake

Reputation: 199805

This isn't the correct approach. Instead, you should listen for navigation events and hide the BottomNavigationView when you're on the login graph:

navController.addOnDestinationChangedListener { _, destination, _ ->
  if(destination.parent!!.id == R.id.login_graph) {
    toolbar.visibility = View.GONE
    bottomNavigationView.visibility = View.GONE
  } else {
    toolbar.visibility = View.VISIBLE
    bottomNavigationView.visibility = View.VISIBLE
  }
}

Then, you can use just a single graph, following the best practices for user login.

Upvotes: 2

Related Questions