I use single Activity patern in my project.In one of the fragments, let's call it ExploreFragment(), I need to create a FragmentContainerView where several fragments will change. The ExploreFragment() has a search engine and by default displays a MovieGanresFragment() with a list of genres. If I start typing text into the search engine, the fragment changes to MovieByNameFragment() where a list of movies with the name entered by the user is displayed. The question is, how do I implement ExploreFragment() where there will be a container with several fragments and all this using the Navigation component?
I decided to create a ExploreFragment() in the main graph and create a FragmentContainerView in it to switch the two fragments MovieGanresFragment() and MovieByNameFragment() . For switching fragments in ExploreFragment() I use childFragmentManager
private fun switchFragment(movieName: String) {
val searchMovieByNameFragment = SearchMovieByNameFragment.newInstanceSearchMovieByNameFragment(movieName)
openScreenWithMovies(searchMovieByNameFragment)
childFragmentManager.beginTransaction()
.replace(
R.id.fragment_container_explore,
searchMovieByNameFragment
)
.addToBackStack(null)
.commit()
}
It works, but there was another question. How to navigate from the MovieByNameFragment() fragment which is not in the main graph to the MoieDetailsFragment() fragment which is in the main graph and pass the data there?
Thsi is 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/welcome_screen">
<fragment
android:id="#+id/moviesFragment"
android:name="com.example.movies.ui.movies.MoviesFragment"
android:label="Home"
tools:layout="#layout/fragment_movies">
<action
android:id="#+id/action_moviesFragment_to_movieDetailsFragment"
app:destination="#id/movieDetailsFragment"
app:enterAnim="#anim/enter_from_right"
app:exitAnim="#anim/exit_to_right" />
<action
android:id="#+id/action_homeFragment_to_moviesFilterFragment"
app:destination="#id/moviesFilterFragment"
app:enterAnim="#anim/enter_from_top"
app:exitAnim="#anim/exit_to_bottom" />
</fragment>
<fragment
android:id="#+id/movieDetailsFragment"
android:name="com.example.movies.ui.move_details.MovieDetailsFragment"
tools:layout="#layout/fragment_movie_details" >
<argument
android:name="movieId"
app:argType="integer"/>
<argument
android:name="showSavedIcon"
app:argType="boolean"/>
<action
android:id="#+id/action_movieDetailsFragment_self"
app:destination="#id/movieDetailsFragment"
app:enterAnim="#anim/enter_from_right"
app:exitAnim="#anim/exit_to_right" />
</fragment>
<fragment
android:id="#+id/saved_movies"
android:name="com.example.movies.ui.saved_movie.SavedMovieFragment"
android:label="Watch list"
tools:layout="#layout/fragment_saved_movie">
<action
android:id="#+id/action_saved_movies_to_movieDetailsFragment"
app:destination="#id/movieDetailsFragment"
app:enterAnim="#anim/enter_from_right"
app:exitAnim="#anim/exit_to_right" />
</fragment>
<fragment
android:id="#+id/nav_login_fragment"
android:name="com.example.movies.ui.login.LoginFragment"
android:label="fragment_login"
tools:layout="#layout/fragment_login">
<action
android:id="#+id/action_nav_login_fragment_to_homeFragment"
app:destination="#id/moviesFragment"
app:popUpTo="#id/nav_login_fragment"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/settings"
android:name="com.example.movies.ui.settings.SettingsFragment"
android:label="Settings">
<action
android:id="#+id/action_settings_to_nav_login_fragment"
app:destination="#id/nav_login_fragment"
app:popUpTo="#id/moviesFragment"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/welcome_screen"
android:name="com.example.movies.ui.welcome_screen.WelcomeScreenFragment"
android:label="fragment_welcome_screen"
tools:layout="#layout/fragment_welcome_screen">
<action
android:id="#+id/action_welcomeScreenFragment_to_nav_login_fragment"
app:destination="#id/nav_login_fragment"
app:popUpTo="#id/welcome_screen"
app:popUpToInclusive="true" />
<action
android:id="#+id/action_welcome_screen_to_homeFragment"
app:destination="#id/homeFragment"
app:popUpTo="#id/welcome_screen"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/moviesFilterFragment"
android:name="com.example.movies.ui.movie_filter.MoviesFilterFragment"
tools:layout="#layout/fragment_movies_filter">
<action
android:id="#+id/action_moviesFilterFragment_to_homeFragment"
app:destination="#id/moviesFragment"
app:popUpTo="#id/moviesFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="#+id/homeFragment"
android:name="com.example.movies.ui.home.HomeFragment"
android:label="fragment_home"
tools:layout="#layout/fragment_home" >
<action
android:id="#+id/action_homeFragment_to_moviesFragment"
app:destination="#id/moviesFragment" />
<action
android:id="#+id/action_homeFragment_to_movieDetailsFragment"
app:destination="#id/movieDetailsFragment"
app:enterAnim="#anim/enter_from_right"
app:exitAnim="#anim/exit_to_right" />
</fragment>
<fragment
android:id="#+id/explore_fragment"
android:name="com.example.movies.ui.explore.ExploreFragment"
android:label="Explore"
tools:layout="#layout/fragment_explore">
<action
android:id="#+id/action_exploreFragment_to_moviesFragment"
app:destination="#id/moviesFragment" />
</fragment>
</navigation>
This is XML of ExploreFragment()
<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:orientation="vertical"
tools:context=".ui.explore.ExploreFragment">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/home_page_toolbar_color"
android:theme="#style/ToolBarStyle"
android:elevation="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView
android:id="#+id/card_view_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
app:cardCornerRadius="32dp"
app:cardElevation="12dp"
app:layout_constraintTop_toBottomOf="#id/toolbar">
<androidx.appcompat.widget.SearchView
android:id="#+id/search_view"
android:layout_width="match_parent"
android:layout_height="34dp"
android:background="#drawable/background_search_view"
app:iconifiedByDefault="false"
app:queryHint="#string/search_view_hint"
tools:ignore="RtlSymmetry" />
</androidx.cardview.widget.CardView>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragment_container_explore"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="15dp"
android:name="com.example.movies.ui.movie_categories.MovieCategoriesFragment"
app:layout_constraintTop_toBottomOf="#id/card_view_search"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Related
I'm building a notes application. I want to save the note when user press the back button from the createsNotesFragment and finish the createNotesFragment so that I can move to the homeFragment.
The code I've used to do this is below:
activity?.onBackPressedDispatcher?.addCallback(this){
saveNote()
activity?.supportFragmentManager?.popBackStack()
}
This is working fine. But when I try to again open the createNotesFragment to add an another note it shows me this error.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.lavanianotesapp, PID: 4952
java.lang.IllegalArgumentException: Navigation action/destination com.example.lavanianotesapp:id/action_homeFragment_to_createNotesFragment cannot be found from the current destination Destination(com.example.lavanianotesapp:id/createNotesFragment) label=fragment_create_notes class=com.example.lavanianotesapp.UI.Fragments.CreateNotesFragment
at androidx.navigation.NavController.navigate(NavController.kt:1540)
at androidx.navigation.NavController.navigate(NavController.kt:1472)
at androidx.navigation.NavController.navigate(NavController.kt:1454)
at androidx.navigation.NavController.navigate(NavController.kt:1437)
Here is my nav Graph
<?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/nav_graph"
app:startDestination="#id/homeFragment">
<fragment
android:id="#+id/homeFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.HomeFragment"
android:label="fragment_home"
tools:layout="#layout/fragment_home" >
<action
android:id="#+id/action_homeFragment_to_createNotesFragment"
app:destination="#id/createNotesFragment" />
<action
android:id="#+id/action_homeFragment_to_editNotesFragment"
app:destination="#id/editNotesFragment" />
</fragment>
<fragment
android:id="#+id/createNotesFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.CreateNotesFragment"
android:label="fragment_create_notes"
tools:layout="#layout/fragment_create_notes" >
<action
android:id="#+id/action_createNotesFragment_to_homeFragment"
app:destination="#id/homeFragment" />
<action
android:id="#+id/action_createNotesFragment_to_addLabelFragment"
app:destination="#id/addLabelFragment" />
</fragment>
<fragment
android:id="#+id/editNotesFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.EditNotesFragment"
android:label="fragment_edit_notes"
tools:layout="#layout/fragment_edit_notes" >
<action
android:id="#+id/action_editNotesFragment_to_homeFragment"
app:destination="#id/homeFragment" />
<action
android:id="#+id/action_editNotesFragment_to_addLabelFragment"
app:destination="#id/addLabelFragment" />
</fragment>
<fragment
android:id="#+id/addLabelFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.AddLabelFragment"
android:label="fragment_add_label"
tools:layout="#layout/fragment_add_label" >
<action
android:id="#+id/action_addLabelFragment_to_createNotesFragment"
app:destination="#id/createNotesFragment" />
<action
android:id="#+id/action_addLabelFragment_to_editNotesFragment"
app:destination="#id/editNotesFragment" />
</fragment>
</navigation>
I don't understant why after popBackStack() I'm not able to open the createNotesFragment again.
Is there any alternative of popBackStack or what I'm missing?
you could try check current destination of your current screen like this:
//id = nav graph fragment id
if (findNavController().currentDestination?.id == id) {
//do something here
findNavController().popBackStack()
}
nav Graph file,
<fragment
android:id="#+id/createNotesFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.CreateNotesFragment"
android:label="#string/fragment_create_notes"
tools:layout="#layout/fragment_create_notes">
<action
android:id="#+id/action_createNotesFragment_to_homeFragment"
app:destination="#id/nav_home"
app:launchSingleTop="true"
app:popUpTo="#id/nav_trip"
app:popUpToInclusive="true">
<argument
android:name="trip_info_response"
android:defaultValue="#null"
app:argType="com.example.lavanianotesapp.UI.entities.TripInfoData"
app:nullable="true" />
</action>
User press the back button from the createsNotesFragment file,
activity?.onBackPressedDispatcher?.addCallback(this){
saveNote()
findNavController().popBackStack()
}
Given I have a Jetpack Navigation Graph as below, where by
BlankFragment1 -> BlankFragment2 -> BlankFragment3 -> BlankFragment4 -> BlankFragment5
<?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/blankFragment1">
<fragment
android:id="#+id/blankFragment1"
android:name="com.example.cashdog.cashdog.BlankFragment1"
android:label="#string/label_blank1"
tools:layout="#layout/fragment_blank1" >
<action
android:id="#+id/action_blankFragment1_to_blankFragment2"
app:destination="#id/blankFragment2" />
</fragment>
<fragment
android:id="#+id/blankFragment2"
android:name="com.example.cashdog.cashdog.BlankFragment2"
android:label="#string/label_blank2"
tools:layout="#layout/fragment_blank2" >
<action
android:id="#+id/action_blankFragment2_to_blankFragment3"
app:destination="#id/blankFragment3" />
</fragment>
<fragment
android:id="#+id/blankFragment3"
android:name="com.example.cashdog.cashdog.BlankFragment3"
android:label="#string/label_blank3"
tools:layout="#layout/fragment_blank3" >
<action
android:id="#+id/action_blankFragment3_to_blankFragment4"
app:destination="#id/blankFragment4" />
</fragment>
<fragment
android:id="#+id/blankFragment4"
android:name="com.example.cashdog.cashdog.BlankFragment4"
android:label="#string/label_blank4"
tools:layout="#layout/fragment_blank4" >
<action
android:id="#+id/action_blankFragment4_to_blankFragment5"
app:destination="#id/blankFragment5" />
</fragment>
<fragment
android:id="#+id/blankFragment5"
android:name="com.example.cashdog.cashdog.BlankFragment5"
android:label="#string/label_blank5"
tools:layout="#layout/fragment_blank5" />
</navigation>
If I have another Fragment, named FragmentSomething, that can be open by and of the FragmentBlank1 to FragentBlank5
Is there a way to update the NavGraph above for my FragmentSomething, without the need to add actions for all 5 of them?
Apparently, there's something called the global action
https://developer.android.com/guide/navigation/navigation-global-action
We just need to add this
<action android:id="#+id/action_global_somethingFragment"
app:destination="#id/somethingFragment"/>
<fragment
android:id="#+id/somethingFragment"
android:name="com.example.cashdog.cashdog.SomethingFragment"
android:label="#string/label_something"
tools:layout="#layout/fragment_something" />
Or we can navigate the code directly to somethingFragment using
findNavController().navigate(R.id.somethingFragment)
I have created my navigation and menu files in the res directory for a bottom navigation view using navigation UI.
I have also set my navigation host fragment within the activity main xml file and the nav controller for my bottom navigation view within the main activity class.
There are three navigation graphs and one main navigation file including the three graphs with the include tag which is referenced in the navigation host fragment in the nav graph property.
I tried switching the background color for each one of the fragments to check if the bottom navigation view is working but all fragments remain white.
Here is my code
Navigation files
First graph
<?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/nav_graph_home"
app:startDestination="#id/home_dest">
<fragment
android:id="#+id/home_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.HomeFragment"
android:label="RecommendedTrips"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/action_home_to_activities_and_points_of_interest"
app:destination="#+id/activities_and_points_of_interest_dest"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_exit_anim"
app:popExitAnim="#anim/nav_default_enter_anim"
/>
<action
android:id="#+id/action_home_to_cities"
app:destination="#+id/cities_dest"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_exit_anim"
app:popExitAnim="#anim/nav_default_enter_anim"
/>
</fragment>
<fragment
android:id="#+id/activities_and_points_of_interest_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.ActivitiesAndPointsOfInterestFragment"
android:label="Activities and points of interest"
tools:layout="#layout/fragment_activities_and_points_of_interest"
>
<action
android:id="#+id/action_activities_and_points_of_interest_to_activities_detail"
app:destination="#+id/activity_detail_dest"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_exit_anim"
app:popExitAnim="#anim/nav_default_enter_anim"
/>
<action
android:id="#+id/action_activities_and_points_of_interest_to_point_of_interest_detail"
app:destination="#+id/point_of_interest_detail_dest"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_exit_anim"
app:popExitAnim="#anim/nav_default_enter_anim"
/>
</fragment>
<fragment
android:id="#+id/cities_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.CitiesFragment"
android:label="Cities"
tools:layout="#layout/fragment_cities"
>
<action
android:id="#+id/cities_to_action_activities_and_points_of_interest"
app:destination="#+id/activities_and_points_of_interest_dest"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_exit_anim"
app:popExitAnim="#anim/nav_default_enter_anim"
/>
</fragment>
<fragment
android:id="#+id/activity_detail_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.ActivityDetailFragment"
android:label="Activity"
tools:layout="#layout/fragment_activity_detail"
>
</fragment>
<fragment
android:id="#+id/point_of_interest_detail_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.PointOfInterestDetailFragment"
android:label="Point of interest"
tools:layout="#layout/fragment_local_point_of_interest_detail"
>
</fragment>
</navigation>
Second graph
<?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/nav_graph_my_trips"
app:startDestination="#id/my_trips_dest">
<fragment
android:id="#+id/my_trips_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.MyTripsFragment"
android:label="My trips"
tools:layout="#layout/fragment_my_trips"
>
<action
android:id="#+id/action_my_trips_to_local_activities_and_points_of_interest"
app:destination="#+id/local_activities_and_points_of_interest_dest"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_exit_anim"
app:popExitAnim="#anim/nav_default_enter_anim"
/>
</fragment>
<fragment
android:id="#+id/local_activities_and_points_of_interest_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.LocalActivitiesAndPointsOfInterestFragment"
android:label="My activities and points of interest"
tools:layout="#layout/fragment_local_activities_and_points_of_interest"
>
<action
android:id="#+id/local_activities_and_points_of_interest_to_local_activity_detail"
app:destination="#+id/local_activity_detail_dest"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_exit_anim"
app:popExitAnim="#anim/nav_default_enter_anim"
/>
<action
android:id="#+id/local_activities_and_points_of_interest_to_local_point_of_interest_detail"
app:destination="#+id/local_point_of_interest_detail_dest"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_exit_anim"
app:popExitAnim="#anim/nav_default_enter_anim"
/>
</fragment>
<fragment
android:id="#+id/local_activity_detail_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.LocalActivityDetailFragment"
android:label="Activity title"
tools:layout="#layout/fragment_local_activity_detail"
>
</fragment>
<fragment
android:id="#+id/local_point_of_interest_detail_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.LocalActivityDetailFragment"
android:label="Activity title"
tools:layout="#layout/fragment_local_activity_detail"
>
</fragment>
</navigation>
Third graph
<?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:tool="http://schemas.android.com/tools"
android:id="#+id/nav_graph_settings"
app:startDestination="#id/settings_dest">
<fragment
android:id="#+id/settings_dest"
android:name="io.keepcoding.mvvmarchitecture.ui.SettingsFragment"
android:label="Settings"
tool:layout="#layout/fragment_settings"
>
</fragment>
</navigation>
Menu file for bottom navigation view
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/nav_graph_home"
android:icon="#drawable/ic_home"
android:title="Main" />
<item
android:title="My trips"
android:id="#+id/nav_graph_my_trips"
android:icon="#drawable/ic_my_trips" />
<item
android:title="Settings"
android:id="#+id/nav_graph_settings"
android:icon="#drawable/ic_settings"
/>
</menu>
Main graph file with include tags
<?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"
android:id="#+id/nav_graph"
app:startDestination="#+id/nav_graph_home"
>
<include app:graph="#navigation/nav_graph_home"/>
<include app:graph="#navigation/nav_graph_my_trips"/>
<include app:graph="#navigation/nav_graph_settings"/>
</navigation>
Activity main xml file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".ui.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/Theme.MVVMArchitecture.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/Theme.MVVMArchitecture.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/navHostContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_marginTop="130dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_above="#id/bottomNavigation"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?android:attr/windowBackground"
app:menu="#menu/tab_bar_menu" />
</RelativeLayout>
Activity main kotlin file
package io.keepcoding.mvvmarchitecture.ui
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import io.keepcoding.mvvmarchitecture.R
import kotlinx.android.synthetic.main.activity_main.*
#Suppress("CAST_NEVER_SUCCEEDS")
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.navHostContainer) as NavHostFragment // We suppress cast never succeeds so the compiler does not complain
val navController = navHostFragment.navController
bottomNavigation.setupWithNavController(navController)
}
private fun loadFragment(fragment: Fragment){
supportFragmentManager.beginTransaction()
.replace(R.id.navHostContainer, fragment)
.commit()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId) {
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
}
}
}
I have 3 top-destination fragments (let's say fragments A, B, C). I can navigate between tabs as expected. However, when i navigate to another fragment from top-destination fragment (fragment A -> fragment A1), I encounter next issue:
When i navigate to another top-destination fragment through bottom nav view, and navigate back (fragment A1 -> fragment B -> fragment A). App opens fragment A1 instead of fragment A and tab B is highlighted as active. Clicking on tab A do nothing.
What is the issue? Here is my setup.
Top-destination fragments are: profile, tools_library, settings
MainActivity.kt
val navView: BottomNavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_main)
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_profile, R.id.navigation_tools_library,
R.id.navigation_settings
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(
navController)
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">
<fragment
android:id="#+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
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/mobile_navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppTheme.BottomNavigationView"
app:elevation="0dp"
app:itemIconTint="#color/bottom_nav_color_selector"
app:itemTextAppearanceActive="#style/BottomNavigationView.Active"
app:itemTextAppearanceInactive="#style/BottomNavigationView"
app:itemTextColor="#color/bottom_nav_color_selector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/bottom_nav_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
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_profile">
<fragment
android:id="#+id/navigation_profile"
android:name="com.example.pocketpsy.presentation.profile.ProfileFragment"
android:label="#string/profile"
tools:layout="#layout/fragment_profile" />
<fragment
android:id="#+id/navigation_tools_library"
android:name="com.example.pocketpsy.presentation.toolslibrary.ToolsLibraryFragment"
android:label="#string/tool"
tools:layout="#layout/fragment_tools_library">
<action
android:id="#+id/navigate_to_description"
app:destination="#id/navigation_description" />
<action
android:id="#+id/navigate_to_tool"
app:destination="#id/navigation_tool" />
</fragment>
<fragment
android:id="#+id/navigation_description"
android:name="com.example.pocketpsy.presentation.description.DescriptionFragment">
<argument
android:name="toolID"
app:argType="string" />
<action
android:id="#+id/navigate_to_tool"
app:destination="#id/navigation_tool"
app:popUpTo="#id/navigation_tools_library" />
</fragment>
<fragment
android:id="#+id/navigation_tool"
android:name="com.example.pocketpsy.presentation.tool.ToolFragment"
android:label="#string/tool"
tools:layout="#layout/fragment_tool">
<argument
android:name="toolID"
app:argType="string" />
<action
android:id="#+id/navigate_to_results"
app:destination="#id/navigation_results" />
</fragment>
<fragment
android:id="#+id/navigation_results"
android:name="com.example.pocketpsy.presentation.results.ResultsFragment"
android:label="#string/results">
<argument
android:name="toolID"
app:argType="string" />
<argument
android:name="resultsID"
app:argType="string" />
</fragment>
<fragment
android:id="#+id/navigation_settings"
android:name="com.example.pocketpsy.presentation.settings.SettingsFragment"
android:label="fragment_settings"
tools:layout="#layout/fragment_settings" />
How i navigate from tools_library fragment to description fragment or tool fragment:
val action: NavDirections
if (toolViewModel.toolDataMap.value!!.isEmpty()) {
action = ToolsLibraryFragmentDirections.navigateToDescription(toolID)
findNavController().navigate(action)
} else {
action = ToolsLibraryFragmentDirections.navigateToTool(toolID)
findNavController().navigate(action)
}
I'm using the Navigation Component and I have 1 Activity with 3 fragments (startDestination: mainFragment , levelFragment and gameFragment). if I'm in levelFragment, it returns to mainFragment, and if I'm in gameFragment it should return to levelFragment, but it returns to mainFragment instead.
I followed the documentation in order to solve the problem but I didn't find any solutions and it's still happening, Why?
Note: gameFragment returns to levelFragment(it appears for just a split second) then immediately returns to mainFragment.
Here's my navigation.xml :
<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/main_nav"
app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="com.hroub.physicsapp.MainFragment"
android:label="fragment_main"
tools:layout="#layout/fragment_main" >
<action
android:id="#+id/action_mainFragment_to_levelFragment"
app:destination="#id/levelFragment"
app:enterAnim="#android:anim/fade_in"
app:exitAnim="#android:anim/fade_out"
app:popEnterAnim="#android:anim/fade_in"
app:popExitAnim="#android:anim/fade_out" />
</fragment>
<fragment
android:id="#+id/gameFragment"
android:name="com.hroub.physicsapp.GameFragment"
android:label="fragment_game"
tools:layout="#layout/fragment_game" >
<argument
android:name="index"
app:argType="integer"
android:defaultValue="0" />
<argument
android:name="concept"
app:argType="com.hroub.physicsapp.model.Concept" />
<action
android:id="#+id/action_gameFragment_to_levelFragment"
app:destination="#id/levelFragment"
app:popUpTo="#id/levelFragment"
app:popUpToInclusive="true"
/>
</fragment>
<fragment
android:id="#+id/levelFragment"
android:name="com.hroub.physicsapp.LevelFragment"
android:label="fragment_level"
tools:layout="#layout/fragment_level" >
<action
android:id="#+id/action_levelFragment_to_gameFragment"
app:destination="#id/gameFragment"
app:enterAnim="#android:anim/fade_in"
app:exitAnim="#android:anim/fade_out"
app:popEnterAnim="#android:anim/fade_in"
app:popExitAnim="#android:anim/fade_out" />
<argument
android:name="position"
app:argType="integer"
android:defaultValue="0" />
</fragment>
Code to navigate to levelFragment :
MainFragmentDirections.ActionMainFragmentToLevelFragment action = MainFragmentDirections.actionMainFragmentToLevelFragment();
action.setPosition(getLayoutPosition());
Navigation.findNavController((Activity)context, R.id.main_host).navigate(action);
Code to navigate to gameFragment :
LevelFragmentDirections.ActionLevelFragmentToGameFragment action = LevelFragmentDirections.actionLevelFragmentToGameFragment(concept);
action.setIndex(getLayoutPosition());
action.setConcept(concept);
Navigation.findNavController((Activity)context, R.id.main_host).navigate(action);
from gameFragment to levelFragment :
Navigation.findNavController(requireActivity(), R.id.main_host).navigate(R.id.action_gameFragment_to_levelFragment);