When I add the View Host Fragment, the design becomes invisible in the xml section, what can I do?
While navigating in Android Studio, when I add nav host fragment to the xml part, the design side becomes invisible, what can I do?
If you encounter such a problem, do not forget to give tools to the xml side in the navigation section, and do not forget to set the constrait to the nav host.
Navigation xml into
xmlns:tools="http://schemas.android.com/tools"
For example
<fragment
android:id="#+id/firstfragment"
android:name="com.example.countryapps.firstfragment"
tools:layout="#layout/fragment_firstfragment"
android:label="firstfragment" >
<action
android:id="#+id/action_firstfragment_to_secondfragment"
app:destination="#id/secondfragment" />
</fragment>
Related
I'm using BottomNavigationView with Navigation Component. When showing fragment is not root fragment, the tab icon is not updated (selected).
Example:
When I switch between Tab Home with Fragment A (which is root fragment) and Tab Star with Fragment B (which is also root fragment) it is working fine.
But when I navigate from Tab Home to another fragment, like fragment A2, and tap on Tab Star and again return to Tab Home, still Tab Star is selected in BottomNavigationView.
It was working fine with version 2.4.0-alpha05, This is happening when I updated it to 2.5.0-alpha01.
build.gradle (app)
implementation "androidx.navigation:navigation-fragment-ktx:2.5.0-alpha01"
implementation "androidx.navigation:navigation-ui-ktx:2.5.0-alpha01"
implementation "androidx.navigation:navigation-dynamic-features-fragment:2.5.0-alpha01"
build.gradle (root)
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.0-alpha01"
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/graph"
app:startDestination="#id/fragmentA">
<fragment
android:id="#+id/fragmentA"
android:name="ui.test.FragmentA"
tools:layout="#layout/fragment_test"
android:label="FragmentA" >
<action
android:id="#+id/action_fragmentA_to_fragmentA2"
app:destination="#id/fragmentA2" />
</fragment>
<fragment
android:id="#+id/fragmentA2"
android:name="ui.test.FragmentA2"
tools:layout="#layout/fragment_test"
android:label="FragmentA2" />
<fragment
android:id="#+id/fragmentB"
android:name="ui.test.FragmentB"
tools:layout="#layout/fragment_test"
android:label="FragmentB" />
</navigation>
Menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/fragmentA"
android:icon="#drawable/ic_home"
android:title="" />
<item
android:id="#+id/fragmentB"
android:icon="#drawable/ic_star"
android:title="" />
</menu>
Am I doing something wrong? or this is bug?
How can I resolve this problem?
So what worked for me was the solution that ianhanniballake hinted at in his answer: using setOnItemSelectedListener.
// always show selected Bottom Navigation item as selected (return true)
bottomNavigationView.setOnItemSelectedListener { item ->
// In order to get the expected behavior, you have to call default Navigation method manually
NavigationUI.onNavDestinationSelected(item, navController)
return#setOnItemSelectedListener true
}
This will always select the item and navigate to the associated destination while maintaining multiple back stacks.
Given your navigation graph, there is no way to associate fragmentA2 with your menu item fragmentA, so fragmentA is not selected when you return to fragmentA2. As per this issue:
NavigationUI has always used the current destination and what graph it is part of as the source of truth for what tab should be selected.
This can be seen by calling navigate() to go to your SecondFragment - even though you haven't used the bottom nav button, the selected tab was changed because the current destination has changed to R.id.frag_second.
So when you navigate() to R.id.frag_hint via your button in HomeFragment, NavigationUI receives a callback that the current destination has changed to R.id.frag_hint. It looks at that NavDestination and notes that there's no menu item that matches R.id.frag_hint. It then looks at the destination's parent graph - your R.id.sample <navigation> element. There's no menu item that matches that ID either, so NavigationUI can't associated that destination with any menu item and therefore simply does nothing. That is true on all versions of Navigation.
So what is different when you tap on a bottom navigation item? Well, nothing different from a NavigationUI perspective in fact: the exact same code runs and the current destination and what graph it is part of is the source of truth for what tab should be selected. In the Navigation 2.3.5, there was no state saved for each tab, so it only 'worked' because selecting a tab forced the ID of the current destination to match the destination of the menu item you just tapped.
So what you're seeing in your sample app is that there's no link between R.id.frag_hint and any menu item, which means NavigationUI does nothing. If you want to link R.id.frag_hint to your Home tab, then that's exactly what a nested navigation graph can be used for.
I.e., your navigation graph should instead look like:
<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/home">
<navigation
android:id="#+id/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"/>
</fragment>
<fragment
android:id="#+id/frag_hint"
android:name="eu.rekisoft.android.navbug.HintFragment"
android:label="Hint"
tools:layout="#layout/fragment_hint"/>
</navigation>
<fragment
android:id="#+id/frag_second"
android:name="eu.rekisoft.android.navbug.SecondFragment"
android:label="Second Fragment"
tools:layout="#layout/fragment_second"/>
</navigation>
And your menu XML should be updated to use android:id="#id/home" to match your navigation graph.
Now, when you select the Home bottom nav item, the current destination changes to R.id.frag_hint (as your state was restored due to Navigation 2.4's support for multiple back stacks) and NavigationUI looks at the ID - R.id.frag_hint still doesn't match any menu item, but now the parent graph's ID, R.id.home does match a menu item - your Home menu item, hence, it becomes selected.
The intention that your navigation graph and its structure drives the UI is a key part of how NavigationUI works and is working as intended (there was a bug on earlier versions of Navigation 2.4 that broke this driving principle, but that has since been fixed in beta02). All of NavigationUI is built on public APIs specifically so that if you want to use some different logic for which bottom nav item is selected that is independent from your navigation graph structure, you can absolutely do that.
You'll note from the source code that you can call the public onNavDestinationSelected with your MenuItem to get the exact same navigate() logic which retaining your own ability to return any value from the setOnItemSelectedListener (which is what controls whether the tab becomes selected). Similarly, your own OnDestinationChangedListener can choose to look at the hierarchy of a destination to choose whether to change the selected bottom nav item or not.
So your graphs should also be using nested graphs for each tab:
<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/graph"
app:startDestination="#id/graphA">
<navigation
android:id="#+id/graphA"
app:startDestination="#id/fragmentA">
<fragment
android:id="#+id/fragmentA"
android:name="ui.test.FragmentA"
tools:layout="#layout/fragment_test"
android:label="FragmentA" >
<action
android:id="#+id/action_fragmentA_to_fragmentA2"
app:destination="#id/fragmentA2" />
</fragment>
<fragment
android:id="#+id/fragmentA2"
android:name="ui.test.FragmentA2"
tools:layout="#layout/fragment_test"
android:label="FragmentA2" />
</navigation>
<navigation
android:id="#+id/graphB"
app:startDestination="#id/fragmentB">
<fragment
android:id="#+id/fragmentB"
android:name="ui.test.FragmentB"
tools:layout="#layout/fragment_test"
android:label="FragmentB" />
</navigation>
</navigation>
Menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/graphA"
android:icon="#drawable/ic_home"
android:title="" />
<item
android:id="#+id/graphB"
android:icon="#drawable/ic_star"
android:title="" />
</menu>
I updated to Navigation 2.4 (def nav_version = "2.4") and now when tapping on a BottomNavigationView item it does not always highlight the icon or show the fragment the BottomNavigationView item id points to.
There are 3 bottom navigation tabs called Home, Actions, My Progress. From the Home fragment, you can navigate to SubFragment.
So the flow might be to start at Home --> go to SubFragment --> go to Actions with the BottomNavigationView --> and then tap on Home to go back. What this did before the update was open the Home fragment (desired behavior). Now when tapping on the Home icon it shows SubFragment and does not highlight the icon.
More details
This is the navController setup:
bottomNavigationView = findViewById(R.id.bottom_navigation_view)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
bottomNavigationView.setupWithNavController(navController)
The nav_graph structure is like this:
<fragment
android:id="#+id/home"
android:name="com.example.app.home"
android:label="Home"
tools:layout="#layout/home"
<action
android:id="#+id/action_home_fragment_to_sub_fragment"
app:destination="#id/sub_fragment"/>
</fragment>
<fragment
android:id="#+id/subfragment"
android:name="com.example.app.subfragment"
android:label="Sub Fragment"
tools:layout="#layout/subfragment" />
<fragment
android:id="#+id/actions"
android:name="com.example.app.actions"
android:label="Actions"
tools:layout="#layout/actions" />
<fragment
android:id="#+id/myprogress"
android:name="com.example.app.myprogress"
android:label="My Progress"
tools:layout="#layout/myprogress" />
The menu items id's for the BottomNavigationView are identical to nav_graph.
I thought the issue might be with the nav_graph structure not playing well with the new SDK, so I tried adjusting the structure of the nav_graph so that each navigation tab was within its own like this question answer has setup. It highlights the tab with this approach but still does not navigate to Home like the example above. Only to SubFragment.
Ideas on what I might be missing are appreciated!
Haven't figured out a fix for the issue yet, so downgraded to def nav_version = "2.3.5" and navigation works properly again.
This is the version before Navigation 2.4 as mentioned by # ianhanniballake above in comments.
I also came across with this issue. It is not a bug in the library.
Actually, when you link menu.xml with nav_graph.xml
You only specified only one fragmentId for each destination. Therefore, it is natural for icon not to change its current state when subfragment is selected.
Instead, you should use nested navigation graphs and use the id of that graph for menu.xml.
<navigation
android:id="#+id/home_destination"
app:startDestination="#id/home" >
<fragment
android:id="#+id/home"
android:name="com.example.app.home"
android:label="Home"
tools:layout="#layout/home"
<action
android:id="#+id/action_home_fragment_to_sub_fragment"
app:destination="#id/sub_fragment"/>
</fragment>
<fragment
android:id="#+id/subfragment"
android:name="com.example.app.subfragment"
android:label="Sub Fragment"
tools:layout="#layout/subfragment" />
</navigation>
<fragment
android:id="#+id/actions"
android:name="com.example.app.actions"
android:label="Actions"
tools:layout="#layout/actions" />
<fragment
android:id="#+id/myprogress"
android:name="com.example.app.myprogress"
android:label="My Progress"
tools:layout="#layout/myprogress" />
And when you are specifying the navigation_menu you will do like this:
<item
android:id="#+id/home_destination"
android:icon="#drawable/ic_read_quran"
android:title="#string/read_quran"
app:showAsAction="always" />
I'm using BottomNavigationView with Navigation Component. When showing fragment is not root fragment, the tab icon is not updated (selected).
Example:
When I switch between Tab Home with Fragment A (which is root fragment) and Tab Star with Fragment B (which is also root fragment) it is working fine.
But when I navigate from Tab Home to another fragment, like fragment A2, and tap on Tab Star and again return to Tab Home, still Tab Star is selected in BottomNavigationView.
It was working fine with version 2.4.0-alpha05, This is happening when I updated it to 2.5.0-alpha01.
build.gradle (app)
implementation "androidx.navigation:navigation-fragment-ktx:2.5.0-alpha01"
implementation "androidx.navigation:navigation-ui-ktx:2.5.0-alpha01"
implementation "androidx.navigation:navigation-dynamic-features-fragment:2.5.0-alpha01"
build.gradle (root)
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.0-alpha01"
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/graph"
app:startDestination="#id/fragmentA">
<fragment
android:id="#+id/fragmentA"
android:name="ui.test.FragmentA"
tools:layout="#layout/fragment_test"
android:label="FragmentA" >
<action
android:id="#+id/action_fragmentA_to_fragmentA2"
app:destination="#id/fragmentA2" />
</fragment>
<fragment
android:id="#+id/fragmentA2"
android:name="ui.test.FragmentA2"
tools:layout="#layout/fragment_test"
android:label="FragmentA2" />
<fragment
android:id="#+id/fragmentB"
android:name="ui.test.FragmentB"
tools:layout="#layout/fragment_test"
android:label="FragmentB" />
</navigation>
Menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/fragmentA"
android:icon="#drawable/ic_home"
android:title="" />
<item
android:id="#+id/fragmentB"
android:icon="#drawable/ic_star"
android:title="" />
</menu>
Am I doing something wrong? or this is bug?
How can I resolve this problem?
So what worked for me was the solution that ianhanniballake hinted at in his answer: using setOnItemSelectedListener.
// always show selected Bottom Navigation item as selected (return true)
bottomNavigationView.setOnItemSelectedListener { item ->
// In order to get the expected behavior, you have to call default Navigation method manually
NavigationUI.onNavDestinationSelected(item, navController)
return#setOnItemSelectedListener true
}
This will always select the item and navigate to the associated destination while maintaining multiple back stacks.
Given your navigation graph, there is no way to associate fragmentA2 with your menu item fragmentA, so fragmentA is not selected when you return to fragmentA2. As per this issue:
NavigationUI has always used the current destination and what graph it is part of as the source of truth for what tab should be selected.
This can be seen by calling navigate() to go to your SecondFragment - even though you haven't used the bottom nav button, the selected tab was changed because the current destination has changed to R.id.frag_second.
So when you navigate() to R.id.frag_hint via your button in HomeFragment, NavigationUI receives a callback that the current destination has changed to R.id.frag_hint. It looks at that NavDestination and notes that there's no menu item that matches R.id.frag_hint. It then looks at the destination's parent graph - your R.id.sample <navigation> element. There's no menu item that matches that ID either, so NavigationUI can't associated that destination with any menu item and therefore simply does nothing. That is true on all versions of Navigation.
So what is different when you tap on a bottom navigation item? Well, nothing different from a NavigationUI perspective in fact: the exact same code runs and the current destination and what graph it is part of is the source of truth for what tab should be selected. In the Navigation 2.3.5, there was no state saved for each tab, so it only 'worked' because selecting a tab forced the ID of the current destination to match the destination of the menu item you just tapped.
So what you're seeing in your sample app is that there's no link between R.id.frag_hint and any menu item, which means NavigationUI does nothing. If you want to link R.id.frag_hint to your Home tab, then that's exactly what a nested navigation graph can be used for.
I.e., your navigation graph should instead look like:
<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/home">
<navigation
android:id="#+id/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"/>
</fragment>
<fragment
android:id="#+id/frag_hint"
android:name="eu.rekisoft.android.navbug.HintFragment"
android:label="Hint"
tools:layout="#layout/fragment_hint"/>
</navigation>
<fragment
android:id="#+id/frag_second"
android:name="eu.rekisoft.android.navbug.SecondFragment"
android:label="Second Fragment"
tools:layout="#layout/fragment_second"/>
</navigation>
And your menu XML should be updated to use android:id="#id/home" to match your navigation graph.
Now, when you select the Home bottom nav item, the current destination changes to R.id.frag_hint (as your state was restored due to Navigation 2.4's support for multiple back stacks) and NavigationUI looks at the ID - R.id.frag_hint still doesn't match any menu item, but now the parent graph's ID, R.id.home does match a menu item - your Home menu item, hence, it becomes selected.
The intention that your navigation graph and its structure drives the UI is a key part of how NavigationUI works and is working as intended (there was a bug on earlier versions of Navigation 2.4 that broke this driving principle, but that has since been fixed in beta02). All of NavigationUI is built on public APIs specifically so that if you want to use some different logic for which bottom nav item is selected that is independent from your navigation graph structure, you can absolutely do that.
You'll note from the source code that you can call the public onNavDestinationSelected with your MenuItem to get the exact same navigate() logic which retaining your own ability to return any value from the setOnItemSelectedListener (which is what controls whether the tab becomes selected). Similarly, your own OnDestinationChangedListener can choose to look at the hierarchy of a destination to choose whether to change the selected bottom nav item or not.
So your graphs should also be using nested graphs for each tab:
<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/graph"
app:startDestination="#id/graphA">
<navigation
android:id="#+id/graphA"
app:startDestination="#id/fragmentA">
<fragment
android:id="#+id/fragmentA"
android:name="ui.test.FragmentA"
tools:layout="#layout/fragment_test"
android:label="FragmentA" >
<action
android:id="#+id/action_fragmentA_to_fragmentA2"
app:destination="#id/fragmentA2" />
</fragment>
<fragment
android:id="#+id/fragmentA2"
android:name="ui.test.FragmentA2"
tools:layout="#layout/fragment_test"
android:label="FragmentA2" />
</navigation>
<navigation
android:id="#+id/graphB"
app:startDestination="#id/fragmentB">
<fragment
android:id="#+id/fragmentB"
android:name="ui.test.FragmentB"
tools:layout="#layout/fragment_test"
android:label="FragmentB" />
</navigation>
</navigation>
Menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/graphA"
android:icon="#drawable/ic_home"
android:title="" />
<item
android:id="#+id/graphB"
android:icon="#drawable/ic_star"
android:title="" />
</menu>
I want to add an explode transition in my next fragment using the latest Navigation pattern "Navigation Graph".How to add a transition XML file(#transition/fade or #transition/slide or #transiton/explode) into Navigation Graph of android app.
You will probably want to define the desired transition in your navigation graph like this:
<fragment
// here your fragment is defined
<action
android:id="#+id/your_action_id"
app:destination="#id/yourDestinationFragment"
app:enterAnim="#anim/fade_in"
app:exitAnim="#anim/fade_out"
app:popEnterAnim="#anim/fade_in"
app:popExitAnim="#anim/fade_out" />
</fragment>
Note that you can define different animations for entering and leaving a fragment.
The animations you define will go into the /res/anim folder. You might have to create it if you don't find it.
I am interested to try the Navigation graph showed in the Android Studio. But I got the preview unavailable after I import the google sample
I used the Android Studio 3.2 Preview Canary 16
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="#+id/launcher_home">
<fragment
android:id="#+id/launcher_home"
android:name="com.android.samples.arch.componentsbasicsample.StartFragment"
android:label="Home">
<action
android:id="#+id/end_action"
app:destination="#id/end_dest" />
</fragment>
<fragment
android:id="#+id/end_dest"
android:name="com.android.samples.arch.componentsbasicsample.EndFragment"
android:label="End"
>
</fragment>
</navigation>
Update on 10/6/2018:
Even I rebuild the project it doesn't work. But if added new screen, it showed the new one in preview mode
You should click on "text" tab in navigation editor (xml file of the navigation graph), and add:
tools:layout="#layout/layout_name"
inside destination element.
Should be something like this:
<fragment
android:id="#+id/someFragment"
android:name="com.freesoulapps.navigationtest.fragments.SomeFragment"
android:label="Some Fragment"
tools:layout="#layout/layout_name">
</fragment>
there is another way to have the preview in navigation xml.
First go in your xml fragment add
tools:context="com.packagename.nameFragment"
And that's it
if you go in your navigation file you can see the preview inside the selection and the navigation editor
And if you look in the code is auto write
tools:layout="#layout/layout_name"
For me is more logic to have the preview before add the fragment in the navigation editor.
May be there are method for add automatically the tools:context in the layout
Autocompletation not suggest for tools:context Fragment only suggest the tools:context Activity host so you need to write the fragment's name... if someone have a trick for this
learn more about tools:context :
enter link description here
Just add
tools:layout="fragmentname"
to every fragment whose preview is not visible.
Example:-
<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/startFragment">
<fragment
android:id="#+id/pickupFragment"
android:name="com.example.cup_cake.PickupFragment"
android:label="fragment_pickup"
tools:layout="#layout/fragment_pickup" />
</navigation>