-1

If I use something like this navController.navigate(R.id.action_nav_home_to_profileFragment) it does navigate me to destination fragment (from my main fragment) because it has action in mainFragment navigation file, but if I'm in other fragments it does not navigate because it doesn't have actions in those fragments.

My question is: is that possible to navigate to my destination fragment from any fragment without using action id? instead using fragment name?

PS: this button is placed in my topbar that's why I need it to be able to navigate from any fragment to destination fragment.

Code

navigation

<fragment
    android:id="@+id/nav_home"
    android:name="irando.co.id.kerjaremote.ui.home.HomeFragment"
    android:label="@string/menu_home"
    tools:layout="@layout/fragment_home" >
    <argument android:name="projectSlugArgument" />
    <action
        android:id="@+id/action_nav_home_to_projectDetailsFragment"
        app:destination="@id/projectDetailsFragment" />
    <argument android:name="searchArgument" />
    <action
        android:id="@+id/action_nav_home_to_searchFragment"
        app:destination="@id/searchFragment" />



    <!--  destination action (works only when I'm in main fragment) -->
    <action
        android:id="@+id/action_nav_home_to_profileFragment"
        app:destination="@id/profileFragment" />
</fragment>

<!-- destination fragment -->
<fragment
    android:id="@+id/profileFragment"
    android:name="irando.co.id.kerjaremote.ui.auth.ProfileFragment"
    android:label="fragment_profile"
    tools:layout="@layout/fragment_profile" />

mainActivity

override fun onOptionsItemSelected(item: MenuItem): Boolean {
  // Handle presses on the action bar menu items
  when (item.itemId) {
    R.id.action_profile -> {
      navController.navigate(R.id.action_nav_home_to_profileFragment)
    }
  }
  return super.onOptionsItemSelected(item)
}

Update

How my navigation works:

I am doing this navigation from my MainActivity which loads fragments.

MainActivity.kt

class MainActivity : AppCompatActivity() {

    lateinit var sesssion: SessionManager
    lateinit var navController: NavController // <--------------------- here
    private lateinit var appBarConfiguration: AppBarConfiguration

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)

        val fab: FloatingActionButton = findViewById(R.id.fab)
        fab.setOnClickListener { view ->
            val intent = Intent(this, PublishActivity::class.java)
            startActivity(intent)
        }

        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.navController // <--------------------- here

        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        val navView: NavigationView = findViewById(R.id.nav_view)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.nav_home, R.id.nav_my_projects, R.id.nav_my_bids, R.id.nav_slideshow
            ), drawerLayout
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.main, menu)
        val action_auth = menu.findItem(R.id.action_auth)
        val action_profile = menu.findItem(R.id.action_profile)
        sesssion = SessionManager(this)

        if (sesssion.isLoggedIn()) {
            action_auth.isVisible = false
            action_profile.isVisible = true
        } else {
            action_auth.isVisible = true
            action_profile.isVisible = false
        }
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        // Handle presses on the action bar menu items
        when (item.itemId) {
            R.id.action_auth -> {
                val i = Intent(this, AuthActivity::class.java)
                startActivity(i)
                return true
            }
            R.id.action_profile -> {
                navController.navigate(R.id.action_nav_to_profileFragment) // <--------------------- here (global action)
            }
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onSupportNavigateUp(): Boolean {
        navController = findNavController(R.id.nav_host_fragment) // <--------------------- here
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }

    // ability of setting top bar title in fragments
    fun setActionBarTitle(title: String?) {
        supportActionBar!!.title = title
    }
}

xml

<?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
        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>
mafortis
  • 6,750
  • 23
  • 130
  • 288

2 Answers2

2

Yes, you can. And you have two choices.

1> create a global action. Check more in this link: https://developer.android.com/guide/navigation/navigation-global-action

2> Navigate by id of fragment. Example:

   android:id="@+id/profileFragment"

navController.navigate(R.id.profileFragment)

NhatVM
  • 1,964
  • 17
  • 25
  • I was just trying `navController.navigate(R.id.profileFragment)` it does work on most fragments but in some it doesn't (not sure why) – mafortis Apr 22 '21 at 02:34
  • in some of my fragments this is the error it gives `Ignoring navigate() call: FragmentManager has already saved its state` – mafortis Apr 22 '21 at 02:36
0

is that possible to navigate to my destination fragment from any fragment without using action id? instead using fragment name?

No you can't use fragment name, but fragment id

Also you can use a global action which allows you to go from any fragment to a particular destination fragment.

This can be done using <action> tag that is directly under <navigation> tag

<navigation ....>

    <fragment
        android:id="@+id/..."

    <action
        android:id="@+id/action_global_profileFragment"
        app:destination="@id/profileFragment" />

</navigation>
Zain
  • 37,492
  • 7
  • 60
  • 84
  • yes i am trying global action now and it says `Ignoring navigate() call: FragmentManager has already saved its state` – mafortis Apr 22 '21 at 02:41
  • Do you move from a fragment to another in the same navGraph, also could you update how do you do that in question – Zain Apr 22 '21 at 02:42
  • Can you `return true` in the `optionsItemSelectied` the case of `R.id.action_profile`, also make sure that the global action `action_nav_to_profileFragment` is directly under the `` not under any other fragment – Zain Apr 22 '21 at 02:51
  • I did all of that already yet error is the same, in some fragments I'm getting `Ignoring navigate() call: FragmentManager has already saved its state` and when I try to open drawer app crash with following error `MainActivity@ff61d9b does not have a NavController set on 2131362110` which is coming from `override fun onSupportNavigateUp(): Boolean {` now i'm not sure which error is the right one :D – mafortis Apr 22 '21 at 02:54
  • Please let me check it thoroughly – Zain Apr 22 '21 at 03:03
  • Can you use the two-arg constructor while using `findNavController()` like `findNavController(this, R.id.nav_host_fragment)` – Zain Apr 22 '21 at 03:18
  • `Too many arguments for public fun Activity.findNavController(viewId: Int): NavController defined in androidx.navigation` – mafortis Apr 22 '21 at 03:42
  • I couldn't reproduce the error.. If possible can you provide a sample demo that we can start off – Zain Apr 22 '21 at 03:45