I have this in app gradle:
apply plugin: 'androidx.navigation.safeargs'
implementation 'android.arch.navigation:navigation-fragment-ktx:1.0.0'
implementation 'android.arch.navigation:navigation-ui-ktx:1.0.0'
and this in the project gradle:
classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0'
the navigation graph:
<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/navigation_graph"
app:startDestination="#id/loginPhoneNumberFragment">
<fragment
android:id="#+id/loginPhoneNumberFragment"
android:name="...fragments.LoginPhoneNumberFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_phone_number">
<action
android:id="#+id/action_loginPhoneNumberFragment_to_loginCodeFragment"
app:destination="#id/loginCodeFragment">
<argument
android:name="prefix"
app:argType="string" />
<argument
android:name="phone_number"
app:argType="string" />
</action>
</fragment>
<fragment
android:id="#+id/loginCodeFragment"
android:name="...LoginCodeFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_code" />
</navigation>
LoginPhoneNumberFragment:
val action = LoginPhoneNumberFragmentDirections.actionLoginPhoneNumberFragmentToLoginCodeFragment(prefix, phoneNumber)
view?.findNavController()?.navigate(action)
LoginCodeFragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val prefix = LoginCodeFragmentArgs.fromBundle(arguments).prefix //LoginCodeFragmentArgs is not recognized
}
In the LoginPhoneNumberFragment it creates the "LoginPhoneNumberFragmentDirections" class, but on the destination class, LoginCodeFragment, it doesn't recognize "LoginCodeFragmentArgs".
Can someone please tell me what am I missing?
(I cleaned and rebuilded, and tried Invalidate caches...)
Ok, so after a lot of searching I found out my mistake -
the arguments should be on the Destination fragment, and not on the starting one:
<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/navigation_graph"
app:startDestination="#id/loginPhoneNumberFragment">
<fragment
android:id="#+id/loginPhoneNumberFragment"
android:name="...fragments.LoginPhoneNumberFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_phone_number">
<action
android:id="#+id/action_loginPhoneNumberFragment_to_loginCodeFragment"
app:destination="#id/loginCodeFragment">
</action>
</fragment>
<fragment
android:id="#+id/loginCodeFragment"
android:name="...fragments.LoginCodeFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_code" >
<argument
android:name="prefix"
app:argType="string"
android:defaultValue="888" />
<argument
android:name="phone_number"
app:argType="string"
android:defaultValue="88888888"/>
</fragment>
</navigation>
You can also add it manually via the navigation graph design - press on the destination fragment and press "+" on the arguments section, it will add it to the text file.
The argument should be in the destination fragment as follows instead of inside the action in source fragment
<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/navigation_graph"
app:startDestination="#id/loginPhoneNumberFragment">
<fragment
android:id="#+id/loginPhoneNumberFragment"
android:name="...fragments.LoginPhoneNumberFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_phone_number">
<action
android:id="#+id/action_loginPhoneNumberFragment_to_loginCodeFragment"
app:destination="#id/loginCodeFragment"/>
</fragment>
<fragment
android:id="#+id/loginCodeFragment"
android:name="...LoginCodeFragment"
android:label="#string/login_activity_title"
tools:layout="#layout/fragment_login_code">
<argument
android:name="prefix"
app:argType="string" />
<argument
android:name="phone_number"
app:argType="string" />
</fragment>
</navigation>
Related
val action = LoginFragmentDirections.actionLoginFragmentToHomeFragment(
User(
_binding.emailEt.editText?.text.toString(),
_binding.passwordEt.editText?.text.toString()
)
)
findNavController().navigate(action)
This is my Button press action
<?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/loginFragment">
<fragment
android:id="#+id/loginFragment"
android:name="com.example.passion.ui.LoginFragment"
android:label="fragment_logins"
tools:layout="#layout/fragment_logins">
<action
android:id="#+id/action_loginFragment_to_homeFragment"
app:destination="#id/homeFragment" />
</fragment>
<fragment
android:id="#+id/homeFragment"
android:name="com.example.passion.ui.HomeFragment"
android:label="fragment_home"
tools:layout="#layout/fragment_home" >
<argument
android:name="user"
app:argType="com.example.passion.data.models.User"
app:nullable="true"
android:defaultValue="#null" />
</fragment>
</navigation>
This is my navigation graph
Everytime I press button. it adds the fragment. I want to replace it with HomeFragment
Any help would be appreciated!. thanks
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 am trying to add a fragment which has implementation done as part of an external framework. Need to include/reference the fragment in the running application. How this can be done?
below is the navigation XML for reference.
<?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/main"
app:startDestination="#id/officeFragment">
<fragment
android:id="#+id/officeFragment"
android:name="com.sample.office.OfficeFragment"
android:label="#string/office">
<argument
android:name="officeId"
app:argType="string"
app:nullable="false" />
<action
android:id="#+id/viewEmployees"
app:destination="#id/profileListFragment"/>
</fragment>
<fragment
android:id="#+id/profileListFragment"
android:name="com.externallibrary.component.people.ui.profilelist.ProfileListFragment"
android:label="#string/people">
<argument
android:name="officeId"
android:defaultValue="#null"
app:argType="string"
app:nullable="true" />
</fragment>
</navigation>
I have the problem that my sample app crashes when I deeplink from one graph part to the other one.
My structure is simple:
Two tabs with own graphs which have each two possible fragments
When I navigate to a detail page (in my sample a book) this just works from my "Shelf" but not from the home screen.
Here is my full 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/sample"
app:startDestination="#id/tab_home">
<navigation
android:id="#+id/tab_home"
app:startDestination="#id/frag_home">
<fragment
android:id="#+id/frag_home"
android:name="eu.rekisoft.android.navbug.HomeFragment"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/cause_bug"
app:destination="#id/frag_hint"/>
<action
android:id="#+id/causeCrash"
app:destination="#id/frag_book">
<argument
android:name="name"
app:argType="string"/>
</action>
</fragment>
<fragment
android:id="#+id/frag_hint"
android:name="eu.rekisoft.android.navbug.HintFragment"
android:label="Hint"
tools:layout="#layout/fragment_hint"/>
</navigation>
<navigation
android:id="#+id/tab_books"
app:startDestination="#id/frag_shelf">
<fragment
android:id="#+id/frag_shelf"
android:name="eu.rekisoft.android.navbug.ShelfFragment"
android:label="Shelf Fragment"
tools:layout="#layout/fragment_shelf">
<action
android:id="#+id/open_book"
app:destination="#id/frag_book">
<argument
android:name="name"
app:argType="string"/>
</action>
</fragment>
<fragment
android:id="#+id/frag_book"
android:name="eu.rekisoft.android.navbug.BookFragment"
android:label="Book Fragment"
tools:layout="#layout/fragment_book">
<argument
android:name="name"
app:argType="string"/>
</fragment>
</navigation>
</navigation>
Here is my crash:
java.lang.IllegalArgumentException: Navigation destination eu.rekisoft.android.navbug:id/frag_book referenced from action eu.rekisoft.android.navbug:id/causeCrash cannot be found from the current destination Destination(eu.rekisoft.android.navbug:id/frag_home) class=eu.rekisoft.android.navbug.HomeFragment
at androidx.navigation.NavController.navigate(NavController.kt:1527)
at androidx.navigation.NavController.navigate(NavController.kt:1464)
at androidx.navigation.NavController.navigate(NavController.kt:1922)
at eu.rekisoft.android.navbug.HomeFragment.onViewCreated$lambda-2$lambda-1(HomeFragment.kt:23)
at eu.rekisoft.android.navbug.HomeFragment.$r8$lambda$q53N5QXeJ-lbbpd7MjwkcKbt9_4(Unknown Source:0)
at eu.rekisoft.android.navbug.HomeFragment$$ExternalSyntheticLambda1.onClick(Unknown Source:2)
Very clear error message, but I don't know how to fix this.
If you want to checkout my code check this GitHub repo.
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);