17

I am a bit confused on how the Navigation component fits in the app behavior. It all looks nice and shiny in tutorials where you don't do things too complex but when implementing in real app, things seem different.

Before Navigation

Before implementing navigation I had to manually run fragment transactions. In order to do this, my fragment would implement an interface onFragmentAction which passed a bundle to the main Activity and in the activity based on the actions, replace the current fragment with another one.

The second part that needs handling is the top toolbar and the BottomAppBar. For instance BottomAppBar needs to have the FAB aligned differently on some fragments or hidden in others. Also the top ToolBar needs to be expanded on some or collapsed on others. To do this, I listened to FragmentManager.OnBackStackChangedListener and based on the fragment tag getSupportFragmentManager().getBackStackEntryAt(size - 1).getName() change the layout accordingly.

With Navigation

The first part seems to be easy to do: pass params and start new fragments. But I have no idea if navigation can handle the toolbars management or I need to keep managing it from my Activity.

Alin
  • 14,809
  • 40
  • 129
  • 218

4 Answers4

21

Even though Alex's solution works, I would not recommend it for the purpose of managing the toolbar.

The toolbar should be part of your fragment's layout and each fragment should manage its own toolbar. you can inflate different menus for each fragment. even in the case of wanting to have the toolbar in the activity, I would recommend getting a reference to the toolbar form activity (through an interface) and then adding and manipulating its items in the fragment itself.

This would decouple your activity and fragment (which is one of the goals of having navigation graph and a router). a good rule of thumb is that imagine you want to remove the fragment, then you should not need to make any change to the activity.

Kayvan N
  • 8,108
  • 6
  • 29
  • 38
  • 1
    Interesting point. But if the activity hosts the toolbar and I manipulate it from the fragment, doesn't the activity need to handle the menu items clicked? So in this case I would still need to update the activity. – Alin Jul 24 '18 at 08:42
  • Not if you have a reference to the toolbar, you can directly register listeners on the items of toolbar in your fragment. I have done all the combinations of this in the past and the least problematic is to handle everything regarding toolbar in the fragment which was one of the main reasons that toolbar is just a view and not a component of the activity. Specially if you might want to change the appbar behavior in some of your fragments and not the others (lets say like using expanded appbar or use the quick back approach) – Kayvan N Jul 24 '18 at 16:34
  • 3
    I think it depends, if I want to have a nice animation where the toolbar hamburger transforms into a backarrow, I suggest the toolbar in the activity and the fragment below it. In that case you can see the toolbar as a navigational concept which should be controlled only by the thing that controls the view, which is the Activity that does Fragment transactions. However, if you add custom stuff into the toolbar, then it would make sense to put it in the fragments, as then it is more part of the control over the fragment than it is just over the navigation between views. – Josttie Sep 19 '18 at 09:15
  • 3
    with this approach every fragment with the same toolbar would re implement the same features, so this solution does not scale well as the app grows – abdu Oct 22 '19 at 13:17
  • do you have sample project implementing this ? :) – sarah Apr 08 '20 at 03:00
7

The toolbar title is set based on 'label' value inside navigation graph, if you want to do something different with toolbar or BottomAppBar you can add addOnNavigatedListener inside your activity, and based on current destination do something.

findNavController(nav_host_fragment).addOnNavigatedListener { controller, 
 destination ->
 when(destination.id) {
    R.id.destination1 -> {
        //Do something with your toolbar or BottomAppBar
    }
    R.id.destination2 -> {
        //Do something with your toolbar or BottomAppBar
    }

 }
}
Alex
  • 9,102
  • 3
  • 31
  • 35
  • there is no `addOnNavigatedListener` interface in implementation 'androidx.navigation:navigation-fragment:2.3.1' – Nanda Z Nov 11 '20 at 03:58
6

In your fragment:

NavController navHostFragment = NavHostFragment.findNavController(this);
NavigationUI.setupWithNavController(toolbar, navHostFragment);

enter image description here

When I click item on list item (Explore Fragment) it will negation to DetailFragment and when I click the back button on the toolbar it will return MainFragment.

Vukašin Manojlović
  • 3,717
  • 3
  • 19
  • 31
Nhật Trần
  • 2,522
  • 1
  • 20
  • 20
3

if you want to reach to another fragment by calling on menu item, you must give to item id the the same id which is in the destination id.

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return 
       item.onNavDestinationSelected(findNavController(R.id.nav_host_fragment))
            || super.onOptionsItemSelected(item)
}


<item android:id="@+id/dailyInfoFragment"
      android:title="@string/action_settings"
      android:orderInCategory="100"
      app:showAsAction="never"/>


    <fragment
        android:id="@+id/dailyInfoFragment"
        android:name="com.example.sonyadmin.infoPerDay.DailyInfoFragment"
        android:label="fragment_daily_info"
        tools:layout="@layout/fragment_daily_info"
        />
Nurseyit Tursunkulov
  • 8,012
  • 12
  • 44
  • 78