I working on a social media App. when user click on a post, a new fragment open and some related post showing under it. if user click on a related post, new instance of that fragment must open and show clicked post and related posts under it. this page also have this behavior. each page must add to back stack.
for using navigation component, in this case destination fragment is current fragment with different argument.
can do this in navigation component?
we can open multiple instace of a fragment by using deeplink
in navigation.xm :
<fragment
android:id="#+id/navigation_profile"
tools:layout="#layout/fragment_profile_owner"
android:label="#string/profile" >
<deepLink
android:id="#+id/profileDeepLink"
app:uri="myapp://?user_id={user_id}" />
</fragment>
and then you can open new fragment by:
findNavController().navigate(Uri.parse("myapp://?user_id=${id}"))
and you can get arguemnt in destination fragment by:
arguments?.getString("user_id")
and put this in activity tag in manifest (if you want to open this page out of app):
<activity
android:name=".ui.activity.MainActivity"
android:label="#string/app_name"
android:screenOrientation="portrait">
<nav-graph android:value="#navigation/navigation" />
</activity>
Related
I need to add the same fragment to different navigation graphs. This is piece of code of first graph (mobile_navigation)
<fragment
android:id="#+id/nav_contactanos"
android:name="com.engie.mexico.micuenta.Fragments.FragmentContactanosCliente"
tools:layout="#layout/fragment_contactanos_cliente" >
<action
android:id="#+id/action_nav_contactanos_to_nav_aviso_privacidad"
app:destination="#id/nav_aviso_privacidad" />
<action
android:id="#+id/action_nav_contactanos_to_nav_terminos_condiciones"
app:destination="#id/nav_terminos_condiciones" />
<action
android:id="#+id/action_nav_contactanos_to_nav_mensaje_usuario"
app:destination="#id/nav_mensaje_usuario" />
</fragment>
The second fragment of code in second navigation graph (navigation_inicial)
<fragment
android:id="#+id/nav_contactanos_cliente"
android:name="com.engie.mexico.micuenta.Fragments.FragmentContactanosCliente"
tools:layout="#layout/fragment_contactanos_cliente" >
<action
android:id="#+id/action_nav_contactanos_cliente_to_nav_mensaje_usuario"
app:destination="#id/nav_mensaje_usuario" />
<action
android:id="#+id/action_nav_contactanos_cliente_to_nav_terminos_condiciones"
app:destination="#id/nav_terminos_condiciones" />
<action
android:id="#+id/action_nav_contactanos_cliente_to_nav_aviso_privacidad"
app:destination="#id/nav_aviso_privacidad" />
</fragment>
When I try to MakeProject, the build output shows me the error :
C:\Android\MiCuenta\app\src\main\java\com\engie\mexico\micuenta\Fragments\FragmentContactanosCliente.java:478: error: cannot find symbol
FragmentContactanosClienteDirections.ActionNavContactanosToNavMensajeUsuario action = symbol: class ActionNavContactanosToNavMensajeUsuario
location: class FragmentContactanosClienteDirections
But when I comment the second piece of code (navigation_inicial), the problem disappears.
The thing is that I need the second piece of code because I need to recall fragment and share with it bundles, with other information and show different things...
How can achieve this?
I also share the design of graphs:
mobile_navigation
mobile_navigation.xml (design)
navigation_inicial
navigation_inicial.xml (design)
The name of the Directions class is based on the name of the Fragment and there can only be one instance of a particular class at a time. As per this issue with Safe Args, there is no warning when you are overwriting one Directions class from one from another graph - the last one wins. This is why reusing the same fragment in a different graph invalidates the Directions class from the first graph.
Of course, if your second graph's fragment has different actions, different arguments, or anything at all different about it, it should have a different fragment class as well - if your single fragment class were to use arguments or actions from another graph, they would fail as they would not exist in that graph.
As mentioned in that bug:
For a destination with an android:name, you'd want to include that android:name in only one place in your graph, referencing that shared destination from all of the places that need access to it (as a destination can access any sibling destinations of their parent graph).
I am learning to use Android fragment navigation.
Now I can follow the sample to use ID to navigate to a specific target fragment defined in the navigation graph. Like following:
<fragment android:id="#+id/a"
android:name="com.example.myapplication.FragmentA"
android:label="a"
tools:layout="#layout/a">
<action android:id="#+id/action_a_to_b"
app:destination="#id/b"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_pop_enter_anim"
app:popExitAnim="#anim/nav_default_pop_exit_anim"/>
</fragment>
viewTransactionsButton.setOnClickListener { view ->
view.findNavController().navigate(R.id.viewTransactionsAction)
}
However, I have a special use case that I want to programmatically navigate to a destination fragment, which is not defined in the navi graph. How can I achieve it like following:
itemView.setOnclickListener { view ->
val targetFragmentClass = getTargetFragmentClass(view)
//How can I findNavController().navigate() to created targetFragmentClass instance?
}
I checked the document of navigation controller, all versions of its navigate() method need some resource ID which means I have to define the action or destination in the XML. But I want something like the legacy fragment manger APIs, which I can instantiate any fragment class and create a transaction to apply it.
So, my questions is:
Can I use navigation component to navigate to any arbitrary fragment purely programmatically?
If I have to use fragment manager/transaction to deal with this case, can I make it work with the navigation controller together?
Thanks a lot.
Here is my code
<fragment
android:id="#+id/fragment1"
android:name="com.example.app.Fragment1"
android:label="SignatureFragment"
tools:layout="#layout/layout_fragment1">
<action
android:id="#+id/action_fragment1_to_main_activity"
app:destination="#id/main_activity"
app:enterAnim="#anim/slide_in_from_right"
app:exitAnim="#anim/no_anim"
app:launchSingleTop="true"
app:popEnterAnim="#anim/no_anim"
app:popExitAnim="#anim/slide_out_to_right"
app:popUpTo="#id/navigation_graph_id"
app:popUpToInclusive="true" />
</fragment>
<activity
android:id="#+id/main_activity"
android:name="com.example.app.MainActivity"
android:label="MainActivity"
tools:layout="#layout/activity_main" />
Now the code for navigation
findNavController().navigate(R.id.action_fragment1_to_main_activity)
When I navigate to activity and press back, the fragment is still there. I want to clear the backstack after opening the activity.
I tried to remove the animation and also tried with removing app:launchSingleTop, but no success.
Edit
Jetpack Navigation is intended to work with single activity and does not fully support activity navigation with parameters passed to actions
Thus to clear stack when navigating from one activity to another you will still need to call activity.finish()
Edit end
The thing is findNavController().navigate(R.id.action_fragment1_to_main_activity) wont work.
Try to navigate via navigate(#NonNull NavDirections directions). In your case it will look something like this
findNavController().navigate(
Fragment1Directions.actionFragment1ToMainActivity())
Hope it helps.
so I have the following navigation graph:
Fragment A (start) --> Fragment B
So for some situations (firebase notifications), I need to start Fragment B directly, passing data from the notifications. Now, this works. However, when I press the back button, it results in a crash. Is it because the leading fragment (Fragment A) is not in the stack? If so, is there a way to properly handle this.
Basically, I need the backPressed action to launch the start Fragment (Fragment A) in a situation where Fragment B is launched directly without passing through Fragment A.
Below is a snippet of my graph:
<fragment
android:id="#+id/homeFragment"
android:name="dita.dev.myportal.ui.home.HomeFragment"
android:label="Home"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/action_homeFragment_to_messageDetailFragment"
app:destination="#id/messageDetailFragment"
app:exitAnim="#anim/fade_out_animation" />
</fragment>
<fragment
android:id="#+id/messageDetailFragment"
android:name="dita.dev.myportal.ui.messages.details.MessageDetailFragment"
android:label="Message"
tools:layout="#layout/fragment_message_detail">
<argument
android:name="title"
app:argType="string" />
<argument
android:name="message"
app:argType="string" />
</fragment>
I hope the link helps.
https://developer.android.com/guide/navigation/navigation-deep-link
Deep links allow for synthetic back-stacks.
Quoted from the website, "This means that when a user presses the Back button from a deep link destination, they navigate back up the navigation stack just as though they entered your app from its entry point."
Maybe trying to create a deep link for Fragment B will work.
I have a graph defined using XML and I added a DialogFragment as one of the Fragment in my NavGraph. when I call NavController.navigate with resId and bundle on that nav controller I don't see any Dialog being displayed. Is there any way I can use DialogFragment instead of standard Fragment?
<fragment
android:id="#+id/noLoginDialog"
android:name="com.ram.view.NoLoginDialog"
android:label="NoLoginDialog">
<argument
android:name="argTitle"
android:defaultValue="null"
app:type="string"/>
<argument
android:name="argBody"
android:defaultValue="null"
app:type="string"/>
<argument
android:name="argButton"
android:defaultValue="null"
app:type="string"/>
</fragment>
and my action is defined as below
<container_fragment
android:id="#+id/homeFragment"
android:name="com.ram.home.HomeFragment"
android:label="HomeFragment">
<action
android:id="#+id/action_homeFragment_to_noAuthAlertDialog"
app:destination="#id/noLoginDialog"/>
</container_fragment>
My other actions with activity and fragments works just fine.
hum, Navigation Library will never open an Fragment as Dialog, it just replace the first (home destination) to other destination in your NavHostFragment.
Google said:
A destination is any place you can navigate to in your app. While
destinations are usually Fragments representing specific screens..
Please provide more information, like your navigation code (java/kotlin).
Take a read on this official Google post to understand more about Navigation:
https://developer.android.com/topic/libraries/architecture/navigation/navigation-implementing
Yes you can call up DialogFragment from navigation, you will just have to explicitly tell the navigation that you are going to use dialog
<dialog
android:id="#+id/simCancelFinish"
android:name="mk.telekom.kiosk.ui.dialogs.SimCancelFinish"
android:label="SimCancelFinish" >
<action
android:id="#+id/action_simCancelFinish_to_stornoSimFragment"
app:destination="#id/stornoSimFragment"
app:popUpTo="#id/stornoSimFragment"
app:popUpToInclusive="true" />
</dialog>