Search code examples
androidandroid-jetpackandroid-jetpack-navigation

Toolbar back button hidden because of start destination


Background

I am trying to use one activity per module where each activity has its own nav graph. So the navigation goes from activity in one dynamic-feature module to another activity in another dynamic-feature module.

Feature1/ActivityA -> Feature2/ActivityB

ActivityA just calls basic startActivity method to launch ActivityB.

Problem

Since ActivityB technically has its fragment at start destination. It doesn't shows up the back button even though I have my ActivityA in my backstack. Is there any way to get around this issue?

PS: Since ActivityA & ActivityB are in 2 separate module I am avoiding to have them under one graph. For activity transition I am just calling startActivity by creating intent using className.

Update - Even if I use nav controller to navigate from ActivityA's fragment to ActivityB, The issue still exists.

ActivityB.xml

</layout>

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/main_toolbar"
            app:navigationIcon="@drawable/ic_back"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:title="@string/title" />

        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/host_container"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:defaultNavHost="true"
            app:navGraph="@navigation/landing_graph" />
    </LinearLayout>

</layout>

ActivityB.kt

internal class ActivityB : AppCompatActivity() {

    private var navController : NavController? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val toolbar = binding.mainToolbar
        navController = supportFragmentManager.findFragmentById(R.id.host_container) as NavHostFragment).navController
        setSupportActionBar(toolbar)
        toolbar.setNavigationOnClickListener { onBackPressed() }
        toolbar.setupWithNavController(navController)
    }

    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp() || super.onSupportNavigateUp()
    }
}

landing_graph.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    app:startDestination="@id/blankFragment">
    <fragment
        android:id="@+id/blankFragment"
        android:name="com.example.cashdog.cashdog.BlankFragment"
        android:label="Blank"
        tools:layout="@layout/fragment_blank" />

    <fragment
        android:id="@+id/blankFragment2"
        android:name="com.example.cashdog.cashdog.BlankFragment2"
        android:label="Blank"
        tools:layout="@layout/fragment_blank_2" />
</navigation>

Solution

  • As per the AppBarConfiguration guide, if you want the Up button to appear on all destinations, even your start destination, you should use the AppBarConfiguration constructor that takes a list of top level destinations. By passing an empty set, every destination will show the Up button.

    Therefore you ActivityB should be:

    internal class ActivityB : AppCompatActivity() {
    
        private var navController : NavController? = null
        private val appBarConfiguration = AppBarConfiguration(emptySet())
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            val toolbar = binding.mainToolbar
            navController = supportFragmentManager.findFragmentById(R.id.host_container) as NavHostFragment).navController
            setSupportActionBar(toolbar)
            // You must always use setupActionBarWithNavController
            // when using setSupportActionBar()
            setupActionBarWithNavController(navController, appBarConfiguration)
        }
    
        override fun onSupportNavigateUp(): Boolean {
            return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
        }
    }