Navigating out of ViewPager tab using Navigation Components - android

First, some clarifications. After looking at a lot of other related questions let's start with what this is not:
This is not about BottomNavigation
This is not about operating the ViewPager using Navigation Components (like this one)
This questions is about how to use Navigation Components, when Viewpager is one of the components.
The situation is having 3 tabs: TabA, TabB, and TabC
Also having 2 extra fragments: FragA, FragB
How do I connect them all so that:
ViewPagerAdapter is handing TabA, TabB, and TabC
AND nav_praph will handle moving from:
TabA --> FragA
TabB --> FragB
TabC --> FragA (not a typo)
Desired UI behavior
First Option: The best I could get working was define the FragHost inside one of the tabs (e.g. TabA) and then navigate to FragA. Problem was the navigation was done INSIDE the tab. Meaning user would still see the tabs on top, and also can still swipe to the other tabs. Not what I wanted.
Here is a diagram of what worked, but is not what I wanted (the red symbolizes the hosting fragment)
Second option: move the fragHost to the very top, and have it contain the ViewPager so it takes up full screen. Then in the nagGraph mention
<navigation
android:id="#+id/nav_graph"
app:startDestination="#id/tab_a"
>
<fragment
android:id="#+id/tab_a"
android:name="com.myapp.home.views.TabA"
android:layout="#layout/tab_a_layout"
>
<action
android:id="#+id/action_tab_a_to_frag_a"
app:destination="#+id/frag_a"
/>
</fragment>
<fragment
android:id="#+id/frag_a"
android:name="com.myapp.FragA"
android:label="details"
android:layout="#layout/frag_a"
/>
This resulted in an IllegalStateException ... at androidx.fragment.app.FragmentStore.addFragment
Some debugging and I saw it was trying to add TabA twice. I assumed both ViewPagerAdapter and Nav Component are using the Fragment manager.
How do I have normal navigation where you can use the tabs, but clicking on one takes you to another full screen experience on top of the tabs?

Figured out the second option I mentioned is the right way to go.
Writing here in case someone else has the same issue.
Make sure your nav_graph is pointing from the containint fragment of the ViewPager and not from the specific fragment the ViewPager is holding.
So not from TabA but from ContainerFragmentA which hosts the ViewPager
<navigation
android:id="#+id/nav_graph"
app:startDestination="#id/view_pager_hosting_frag"
>
<fragment
android:id="#+id/view_pager_hosting_frag"
android:name="com.myapp.home.views.ViewPagerHostingFrag"
android:layout="#layout/view_pager_layout"
>
<action
android:id="#+id/action_tab_a_to_frag_a"
app:destination="#+id/frag_a"
/>
</fragment>
<fragment
android:id="#+id/frag_a"
android:name="com.myapp.FragA"
android:label="details"
android:layout="#layout/frag_a"
/>
Then you can choose the action you want from any of the tabs to go to the right location

Related

NavigationController does not open new fragment if it is already associated with bottom navigation

I have a fragment in bottom navigation when try to launch new fragment with same id using navigation controller instead of launching new fragment it redirects me to bottom navigation tab.
here is my code
<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/home_navigation"
app:startDestination="#id/splashFragment">
<fragment
android:id="#+id/baseTabsFragment"
android:name="com.abc.abc.fragment.BaseTabsFragment"
android:label="BaseTabsFragment"
tools:layout="#layout/fragment_common_tabs">
<action
android:id="#+id/action_to_baseFragment"
app:destination="#id/baseTabsFragment"
app:launchSingleTop="false" />
</fragment>
</navigation>
And code to navigate.
findNavController().navigate(R.id.action_to_baseFragment)
Here is a link for more details on this
https://issuetracker.google.com/issues/262076827
Update: I want to avoid the code duplication. I will have same fragments with same actions but different id's looking for a better way to do it.
If i understand correctly, you want to navigate to the same fragment and fragment does not refresh.
If you use navigation component in visual interface you need to pull an arrow from your baseFragment onto baseFragment again, with this you will see an arrow like self pointed. If you don't use visual just paste below code and it will be created.
<action
android:id="#+id/action_to_BaseFragment"
app:destination="#id/baseTabsFragment"
app:popUpTo="#id/baseTabsFragment"
app:popUpToInclusive="true" />
We are using this way because if we want system to navigate, it needs different location then previous, as long as we using same fragment we need to pop the old one.
It happened due to bottom menu. In this case you need to call programmatically to click on that bottom button.
Replace
findNavController().navigate(R.id.action_to_baseFragment)
to
navController.navigate(
R.id.base_graph, null,
NavOptions.Builder().setPopUpTo(navController.graph.startDestinationId, true).build()
)

How to navigate from Dialog to Fragment in Navigation Component?

I am trying to navigation from DialogFragment to Fragment in Navigation Component, but getting weird result.
When I navigate from DialogFragment to Fragment, background fragment is changing to target fragment with current dialog on top of it, instead of just moving to target fragment.
Here is 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/home"
app:startDestination="#+id/titleScreen">
<fragment
android:id="#+id/titleScreen"
android:name="com.example.android.navigationadvancedsample.homescreen.Title"
android:label="#string/title_home"
tools:layout="#layout/fragment_title">
<action
android:id="#+id/action_title_to_about"
app:destination="#id/aboutScreen"/>
</fragment>
<dialog
android:id="#+id/aboutScreen"
android:name="com.example.android.navigationadvancedsample.homescreen.About"
android:label="#string/title_about"
tools:layout="#layout/fragment_about">
<action
android:id="#+id/action_aboutScreen_to_register"
app:destination="#id/register" />
</dialog>
<fragment
android:id="#+id/register"
android:name="com.example.android.navigationadvancedsample.formscreen.Register"
android:label="fragment_leaderboard"
tools:layout="#layout/fragment_leaderboard" />
</navigation>
Why I am getting this behavior or how to fix it?
By fixing I mean normal dialog behavior. Say, I have a dialog D on top of a fragment A and move to a fragment B from a button on D, the screen should show B. And when I pop back from B, it should go to previous stage of D on top of A.
Thanks #musooff for filing this bug
This problem was fixed on Navigation 2.1.0-alpha06, along with others dialog inconsistencies like back button when Dialog is popped.
However, update to 2.1.0-beta02 or higher if you can.
You could use
view.getDialog().dismiss();
after navigate to B. But in that way, dialog won't be visible when you came back to A fragment.
If you really want it to be visible, maybe you should try to use Fragment and pretend it to be Dialog. Like in these example with activity link.

Put ViewPager in fragment of a menu drawer Android

I searched a solution everywhere but I didnt find anything, so I need one more time your help.
I have a Navigation drawer who works perfectly
Navigation drawer
I have also a ViewPager, that I have take on the Android developer's website. It works fine also.
Now I would like to put the PageViewer in my "jour" tab for exemple. But the PageViewer is not a "Fragment" but a "ActivityFragment" so I cannot. The help that I can find on the other threads does'nt match to my problem
How Can I do this ?
Thanks a lot for reading me.
Annex:
Tutorial Android : https://developer.android.com/training/animation/screen-slide.html
I dont know if i should create a new thread or not. I have put the code in the main activity but the fragment cover all the activity. screen of the fragment
It is strange because the other fragments work.
main Activity
TestSlideFragment fragment = new TestSlideFragment();
fragmentTransaction.replace(R.id.RelativeLayout_for_Fragment, fragment);
fragmentTransaction.commit();
layout of the fragment
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="oytoch.iut_info.test.TestSlideFragment">
<!-- TODO: Update blank fragment layout -->
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/page"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Open your Jour's xml and add the ViewPager Tag.
Then open Jour's java and bind an object of ViewPager with the xml. Add the adapter to the viewpager object and you are done.

Android Fragment for tablets and phone

I want to do something like that. An picture is easier than words:
And when the user clicks on a button on the Fragment B, the fragment B changed but not the A.
I've made two different layout (A portrait and a land one). The first one has a layout like
<?xml version="1.0" encoding="utf-8"?>
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.my.app.ContactsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/contacts_fragment" />
I've a button in my fragment layout with a simple activity call:
Intent intent = new Intent(getActivity(), NextActivity.class);
startActivity(intent);
And the land one is like that:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.my.app.ContactsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/contacts_fragment" />
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.my.app.HomeFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/fragment_container" />
</LinearLayout>
I change the inner fragment using the following code:
FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
NextFragment nextFrag = new NextFragment();
ft.replace(R.id.fragment_container, nextFrag);
ft.addToBackStack(null);
ft.commit();
This part works well.
I have two questions now:
How to put these two ways to change the content in the main activity? I mean, in the main activity, a fragment should call the second way, but in a normal activity, I need to call the first.
If I click on an item in the fragment A, and then I click on the button in fragment B that changes the fragment to NextFragment. If I click on another item and i do the same. I can go back to the first user. Is there a way to dump the stack when clicking on a new item ?
Thanks for your help.
Ps: I'm using the native fragment lib not the support v4.
I'm struggling to understand the specifics of your 2 questions, as they are vague and do not give enough detail.
However, since you want your Fragments to be changed out at runtime, you should not put <fragment/> in your layout files. Your current architecture makes it impossible to change out the Fragments in your layouts, which is not what you want.
Note: When you add a fragment to an activity layout by defining the fragment in the layout XML file, you cannot remove the fragment at runtime. If you plan to swap your fragments in and out during user interaction, you must add the fragment to the activity when the activity first starts.
You should be using FrameLayout containers for your Fragments in your layout files, and have a single Activity add Fragments to those FrameLayout containers depending on if they are there. This will allow the app to create 1 Fragment in portrait and 2 Fragments in landscape (given you have have a layout for each orientation). This will also allow you to be able to swap out Fragments as your please, and add them to the back stack.
And example of this Google recommended approach can be found here.
You can find a good solution from here.

Android fragments overlap after afew rotating screen

I read some questions like it, but I dont understand well what should I do in my hiearchy?
I have
<fragment
android:id="#+id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
class="com.****.****.ui.TabsFragment" />
for tab menu on bottom of screen
and
<FrameLayout
android:id="#+id/details"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/tickerLL"
android:layout_below="#id/header"
android:background="#drawable/background" />
for other will created fragments.
I have 9 tab menus, everyone is a fragment.
Some fragments's landscape are another activity. And I rotate back phone, fragments are working well. But if I rotate fast after and after, My fragment Activty, TabsFragment and and other created fragments are recreated and my fragments are overlapping.
I manage my fragments in TabsFragment. And they works dynamicly, my abstract fragment class, has a previous fragment and subfragment. When I press back, previous fragment closes its subfragment and null it.
What should I do?
During a configuration change, Android restores or recreates all fragments that the old activity had when setting up the new activity. Hence, you need to take that into account when working with the new activity instance -- do not assume that you are starting with a clean slate.

Categories

Resources