NavHostFragment and ViewPager2 doesn't work at the same time - android

I have an app, that has a few fragments in it. I'm using ViewPager 2 to swipe between them.
Lately I've added Navigation component to make a way to get into one specific fragment that is not avilable for user just by swipe.
I've found out, that whever I place FragmentContainerView over the ViewPager2 in my MainActivity layout, I can go to this unvailable fragment, but I can't swipe. Same thing whener I switch FragmentContainerView with ViewPager2. Is there any way to make them both work at the same time?
Here's my layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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=".MainActivity"
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph" />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

They can work together but not like this, at least not for what you want.
Navigation component is made to handle traveling between destinations. ViewPager2 is a widget to be used in a destination, not for traveling between them.
For what you are describing you will need to have FragmentA that will contain ViewPager2 where all of the swiping will take place and handling of fragments (let's say Fragment1, Fragment2, Fragment3) in the ViewPager2.
Those fragments will have nothing to do with the Navigation component.
Navigation component will come to play when you will want to go from FragmentA to FragmentB.

Related

Master-Detail Flow hide detail view

When implementing a Master-Detail Flow with Navigation Components i don't see any possiblity to hide the detail fragment once a navGraph is set. Let's consinder a item in the Master View is selectable and deselectable. When deselcting an Item i cannot remove the StartDestination from the NavGraph.
Consider a Layout like this as the Master-Detail Flow Layout:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/itemList"
android:layout_width="400dp"
android:layout_height="match_parent"/>
<fragment
android:id="#+id/detailContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="false"/>
</LinearLayout>
As soon as i set a NavGraph with a startDestination to the detailContainer i cannot remove or hide it when i unselect the current selected item. The only solution i found so far was to to hide the container.

Android navigation drawer with tab layout in fragment

I am new to android and I am going to design this kind of layout that is complex to me. Here's the code of main_activity.xml file:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.CoordinatorLayout 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=".MainActivity">
<android.support.v4.view.ViewPager
android:id="#+id/home_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout_home"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:layout_gravity="start"
app:headerLayout="#layout/nav_header"
app:menu="#menu/menu_drawer"/>
</android.support.v4.widget.DrawerLayout>
Basically I have in my main activity a Navigation drawer and 3 tabs. Here's a picture:
Everything works as I want and I'm happy.
When I click on a navigation drawer item I start a new intent to open a new activity and it's good but the drawer disappears of course (becase the new activity does NOT have the drawer). I want to keep the drawer in the screen always.
To keep the drawer on my screen I thought that I could have placed the TabLayout of the above XML as a fragment; in this way the drawer would still be there. But how can I do this? How can I place the TabLayout in a fragment so that I can replace this fragment with TabLayout or other fragments?
I think that I could put a FrameLayout instead of TabLayout but I do not know if it's good idea and how would it work. Any help?
There are similar questions like this but they haven't helped me because I'm still stuck here
More. If you click on results, the ThisSeason activity is launched and it has some fragments inside (inclusing ResultsFragments). That works, but there is no navigation drawe anymore and I have to press the back button!
I'll give you a general idea for implementing this.
Make a base activity for your application.
Then make fragment for each activity including the screen which has tabs. So, if you have 5 items in nav view then total of 6 fragments will be created.
Add the nav view and related functions in the main activity xml and java file. This will basically add navigation view to the base activity and since you're using fragments, all the pages(fragments) will have the navigation view.
Additional Note: You can make multiple subclasses to handle specific functions, like one for handling actionMode, navigation view and updating the title in the toolbar. You get the point.
Also, all the features which are common to all the fragments should be added in the base activity only instead of repeating the same code everywhere.

Simple navigation across navigation graphs with Android Navigation Architecture Component

This is a simple example of a navigation setup that I can't get to work with the Navigation Component library, after researching for some time.
Let's say I have the following screen:
The sticky fragment at the top and the fragment at the bottom are in their own navigation graphs, here is the main_activity.xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/nav_sticky_top"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="50dp"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/navigation_graph_sticky_top" />
<fragment
android:id="#+id/navigation_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#id/nav_sticky_top"
app:navGraph="#navigation/navigation_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
When I press "navigate to sibling fragment" it navigates to the sibling fragment inside the bottom navigation graph, which is correct, the result:
This is the navigation_graph.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/navigation_graph.xml"
app:startDestination="#id/blankFragment1">
<fragment
android:id="#+id/blankFragment1"
android:name="com.example.myapplication.BlankFragment1"
android:label="fragment_blank_fragment1"
tools:layout="#layout/fragment_blank_fragment1">
<action
android:id="#+id/action_blankFragment1_to_siblingFragment"
app:destination="#id/siblingFragment" />
</fragment>
<fragment
android:id="#+id/siblingFragment"
android:name="com.example.myapplication.SiblingFragment"
tools:layout="#layout/fragment_sibling_fragment" />
</navigation>
Now I would like to implement the "Navigate to fullscreen fragment" button, which should navigate to a fullscreen fragment which is in a separate, third navigation graph and should be above the sticky fragment navigation graph and the navigation graph below that. How can this be properly achieved? By that I mean without hacks like setting the visibility of the top navigation graph fragment to GONE and navigating in the bottom navigation graph to the fullscreen fragment.
UPDATE: I don't recommend this approach any more. For small apps it may work for you, but I ran into complications when trying to pass data between different navigation graphs hosted inside different NavHostFragments. I think the easiest route is the "hack" of hiding fragments in your top level layout to allow a full screen view. You can add an addOnDestinationChangedListener to listen for destinations that you want full screen, and simply hide the fragment required.
ORIGINAL ANSWER:
I do it like this in my app and it works well. You should wrap all your current fragments in a parent fragment with a main_nav_graph.xml. For example:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/main_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/main_nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
Then your navigation for full screen fragments will look like this:
<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_graph.xml"
app:startDestination="#id/main_fullscreen">
<fragment
android:id="#+id/main_fullscreen"
android:name="com.example.myapplication.MainFullscreen" >
<action
android:id="#+id/action_main_fullscreen_to_fullscreen2"
app:destination="#id/fullscreen2" />
</fragment>
<fragment
android:id="#+id/fullscreen2"
android:name="com.example.myapplication.Fullscreen2" />
</navigation>
Where the MainFullscreen has a layout like your ConstraintLayout you provided. Just make sure you add app:defaultNavHost="true" to all your child NavHostFragments.
Then when I want to navigate from your blankFragment1 to fullscreen2, I call this:
Navigation.findNavController(activity!!, R.id.main_host_fragment).navigate(R.id.action_main_fullscreen_to_fullscreen2)
Granted, there's not much point to having navigation graphs if they are not actually connected except via being in the same activity, but I just like the pretty picture of the app the graphs give you in the navigation editor :)

How to have a view over several activities

How can I have my BottomNavigationView in several activities but without declaring it there?
i declared my Bottom navigation view in my main_activity.xml and handle the click logic within MainActivity class, but since I want to switch between 3 activities (Map, Friends, Chats) with the Bottomnavigationview i'd have to have 3 bottom navigation views over three activities, but since that's performance inefficient, I want to handle all the click events and initialisation of the view inside one class and one Layout
(MainActivity class and main_activity.xml ).
What can I do? or is there a better way of doing this?
You should use fragments instead of activities. Have only 1 activity ie MainActivity, add BottomNavigationView and fragments above the BottomNavigationView. And on clicking the BottomNavigationView, replace the fragments.
Your XML would be something like,
<?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">
<View
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_above="#id/bottom_nav_view"></FrameLayout>
From your activity, add fragments in FrameLayout. Your BottomNavigationView will remain intact. Just replace fragments in this FrameLayout on clicking NavigationView tabs.

Swiping a fragment not full page.

I currently have 1 activity that jas 2 fragments top half and botton half. I want to swipe the bottom fragment only. (java implented)
Before i go learning the wrong method could someone please tell me which method I should use.
Do you sill use pageView and a fragment adapter or something.
Any usefull tutorials that do similar would be good so i can figure it out.
Define fragment and viewpager in the same activity. in the fragment show thetop fragment and in viewpager, write one pager adapter and invoke all the child fragments into that pager. This solves your problem.
Your activity layout:
<?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:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<space
android:id="#+id/layout"
android:layout_width="match_parent"
center_horizontal="true"
center_vertical="true"
android:layout_height="0.5dp">
<fragment
android:id="#+id/layout"
android:layout_width="match_parent"
layout_above="#id/space_layout"
android:layout_height="match_parent"/>
<android.support.v7.widget.viewpager
android:id="#+id/layout"
android:layout_width="match_parent"
layout_below="#id/space_layout"
android:layout_height="match_parent">
Then define PagerAdapter class and show all your child fragments in that.
all the best

Categories

Resources