Search code examples
androidandroid-fragmentstoolbarandroid-jetpack-navigation

How can I use a toolbar in a fragment but not in activity using Jetpack's Navigation


I have start using Android Jetpack's Navigation library. So far, I find it very easy to use. The problem I'm facing is with the toolbar.

What I want to achieve is:

  1. User opens the app and the login page is shown. This is the start of the navigation, and toolbar should not be shown.
  2. If user logs for the first time, a fragment for resetting his password (autogenerated by administrator) will show, so that the user changes it. Here I want ton show a white toolbar with the back arrow in it (and no text)
  3. If user has logged before, we show a loading screen (with no toolbar either)

I've tried so many things but not succeeded. This first two attempts are using an activity with a NoActionBar style.

Toolbar in the Reset password fragment

  • Custom Appbar with toolbar. It is showing, but the back arrow is not shown. I tried adding an Imageview inside my toolbar and I also tried setting the icon from java, but neither of those worked.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
    android:background="@color/white"
    tools:context=".ResetPasswordFragment">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar_resetPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:liftOnScroll="true"
        >

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar_resetPassword"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/white"
            />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:id="@+id/scrollView_resetPassword"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <!-- Linear layout -->

    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Toolbar in the Activity

This attempt worked. It added a toolbar in my activity like this:

<?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"
    android:background="@color/colorAccent"
    android:orientation="vertical"
    tools:context=".LoginActivity">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_height="?attr/actionBarSize"
        android:layout_width="match_parent"
        android:background="@color/white"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />
    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar"
        app:navGraph="@navigation/nav_graph" />

</androidx.constraintlayout.widget.ConstraintLayout >

and in my Controller, I added this:

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        AppBarConfiguration appBarConfiguration =
                new AppBarConfiguration.Builder(navController.getGraph()).build();
        Toolbar toolbar = findViewById(R.id.toolbar);
        NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration);

The problem here is that the toolbar is shown in my first fragment, and I don't want that. I tried removing it from my first fragment and it worked, but when I tried to show it again in my second fragment, for some reason the findViewById didn't recognize my toolbar. So I ended up showing the toolbar again in my first Fragment code, just before the second fragment shows. It worked but you can notice the animation when the toolbar is showing and it doesn't look good, and I know hiding/showing the toolbar directly from my fragment is not ok.

What do I do?

So, what do I need to do achieve this properly? In the future, I'll have an activity with some other fragments too, and I will need a similar behavior as the one I wrote before. I think it will be better if I do this fine since now.

Thanks!


Solution

  • You can Listen for navigation events by using OnDestinationChangedListener. For example :

    navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
       @Override
       public void onDestinationChanged(NavController controller,
           NavDestination destination, Bundle arguments) {
    
           // getting the current fragment id.
           int currentFragmentID = destination.getId();
    
           if(currentFragmentID == R.id.fragment_with_toolbar){
            // showing the toolbar
              toolbar.setVisibility(View.VISIBLE);
            } else if(currentFragmentID == R.id.fragment_without_toolbar){
            // hiding the toolbar
              toolbar.setVisibility(View.GONE);
            }
      }
    });