0

I want to create a single app activty app using Material 3 Bottom Navigation (BN) and Jetpack Navigation. Everything works fine, until one of my fragments set by the BN navigateS to another fragment. When that happens, if I change my fragment via BN again and try to go back to the other fragment, the fragment changes (which was what I expected), but the selected Icon do not (which is weird).

To make it easier to understand, think of the fragments like this:

Fragment Home -> Fragment set by the actionHome icon

Fragment Dashboard -> Fragment set by the actionDashboard icon

Fragment Notifications -> Fragment set by the actionNotifications icon

Fragment Home Two -> Fragment set by a button buttonHomeTwo on the Fragment Home layout.


The navigation flow would be like this:

Click on the actionHome icon

Click on the button buttonHomeTwo

Click on the actionDashboard icon

Click on the actionHome icon


Expected flow:

  1. Navigate to Fragment Home with actionHome selected
  2. Navigate to Fragment Two with actionHome selected
  3. Navigate to Fragment Dashboard with actionDashboard selected
  4. Navigate to Fragment Two with actionHome selected

Actualflow (bug):

  1. Navigate to Fragment Home with actionHome selected
  2. Navigate to Fragment Two with actionHome selected
  3. Navigate to Fragment Dashboard with actionDashboard selected
  4. Navigate to Fragment Two with actionDashboard selected <- here's the bug

To make it even easier to understand, I created a repo with this problem on Github.

But these are some sniptes from the repo:


build.gradle (app)

dependencies {
    implementation 'androidx.core:core-ktx:1.9.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.8.0'

    implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
    implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
}

res/values/themes.xml

<resources>
    <style name="Theme.BottomNavProblem" parent="Base.Theme.BottomNavProblem">
        <item name="android:navigationBarColor">@android:color/transparent</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:windowLightStatusBar">?attr/isLightTheme</item>
    </style>
</resources>

res/navigation/mobile_navigation.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation 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/mobile_navigation"
    app:startDestination="@+id/navigation_home">

    <fragment
        android:id="@+id/navigation_home"
        android:name="com.honkgoose.bottomnavproblem.ui.home.HomeFragment"
        android:label="@string/title_home"
        tools:layout="@layout/fragment_home" />

    <fragment
        android:id="@+id/navigation_dashboard"
        android:name="com.honkgoose.bottomnavproblem.ui.dashboard.DashboardFragment"
        android:label="@string/title_dashboard"
        tools:layout="@layout/fragment_dashboard" />

    <fragment
        android:id="@+id/navigation_notifications"
        android:name="com.honkgoose.bottomnavproblem.ui.notifications.NotificationsFragment"
        android:label="@string/title_notifications"
        tools:layout="@layout/fragment_notifications" />


    <fragment
        android:id="@+id/navigation_home_two"
        android:name="com.honkgoose.bottomnavproblem.ui.hometwo.HomeTwoFragment"
        android:label="@string/title_home_two"
        tools:layout="@layout/fragment_home_two" />

</navigation>

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        WindowCompat.setDecorFitsSystemWindows(window, false)
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val navView: BottomNavigationView = binding.navView

        val navController = findNavController(R.id.nav_host_fragment_activity_main)
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }
}

res/layout/activity_main.xml

<?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"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="0dp"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/bottom_nav_menu" />

    <fragment
        android:id="@+id/nav_host_fragment_activity_main"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@id/nav_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />

</androidx.constraintlayout.widget.ConstraintLayout>

Am I doing something wrong or this is a bug in one of the libraries?

EDIT

I tried to solve the problem by using Jetpack Navigatiom Safe Args, but the same problem happened. the changes are:

build.gradle (project)

plugins {
    ...
    id 'androidx.navigation.safeargs' version '2.5.3' apply false
}

build.gradle (app)

plugins {
    ...
    id 'androidx.navigation.safeargs.kotlin'
}

HomeFragment.kt

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    binding.homeTwoButton.setOnClickListener {
        findNavController().navigate(HomeFragmentDirections.toNavigationHomeTwo())
    }
}

res/navigation/mobile_navigation.xml

<fragment
    android:id="@+id/navigation_home"
    android:name="com.honkgoose.bottomnavproblem.ui.home.HomeFragment"
    android:label="@string/title_home"
    tools:layout="@layout/fragment_home" >

    <action
        android:id="@+id/to_navigation_home_two"
        app:destination="@id/navigation_home_two" />

</fragment>

EDIT 2

I tried to solve the problem by using <FragmentContainerView> instead of <Fragment>, but the same problem happened. the changes are:

activity_main.xml

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/fragment_container_view"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    app:defaultNavHost="true"
    app:layout_constraintBottom_toTopOf="@+id/nav_view"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:navGraph="@navigation/nav_graph" />

MainActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
    val navView: BottomNavigationView = binding.navView
    val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container_view)
    val navController = (fragment as NavHostFragment).navController
    val appBarConfiguration = AppBarConfiguration(
        setOf(
            R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
        )
    )
    setupActionBarWithNavController(navController, appBarConfiguration)
    navView.setupWithNavController(navController)
}
Leonardo Sibela
  • 1,613
  • 1
  • 18
  • 39

0 Answers0