ViewPager vanishes after getting back to the containing fragment - android

I have an activity which have a complex structure of Fragments. The Activity have two containers, each for a NavigationDrawerFragment and a Main Content Fragment(HomeTabFragment). The Main Content Fragment has TabLayout+ViewPager structure containing two child Fragments(Search and News). This has been working well, untill I need to replace Main Content Fragment with another Fragment (Settings). This also worked well, but when I want to get back to the same Main Content Fragment, the ViewPager, along with the child fragments vanishes.
This is structure. HomeTabFragment is replaced by SettingsFragment via a button (In LeftDrawerFragment) and SettingsFragment is again replaced by HomeTabFragment via a button (In LeftDrawerFragment or a hardware back key)
HomeActivity
|-LeftDrawerFragment
|-HomeTabFragment
| |-ViewPager
| |-HomeSearchFragment
| |-HomeNewsFragment
|-SettingsFragment
Here's the HomeActivity layout -
<?xml version="1.0" encoding="utf-8"?>
<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"
android:fitsSystemWindows="true">
<!--<include layout="#layout/content_home"/>-->
<android.support.v4.widget.DrawerLayout android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--Toolbar-->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="center_horizontal"
android:background="?attr/colorPrimary"
android:gravity="center_horizontal"
app:layout_scrollFlags="enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:subtitle="Your Medi-buddy"
app:title="#string/app_name">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#null"
android:onClick="onHomeMenuClick"
android:padding="5dp"
android:src="#drawable/ic_menu_white" />
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/app_name"
android:textAppearance="#android:style/TextAppearance.Holo.Large" />
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<!-- The main content view -->
<FrameLayout
android:id="#+id/tab_frag_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
<!-- The navigation drawer -->
<FrameLayout
android:id="#+id/left_drawer_container"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111" />
</android.support.v4.widget.DrawerLayout>
</android.support.design.widget.CoordinatorLayout>
Following is the layout of my HomeTabFragment
<?xml version="1.0" encoding="utf-8"?>
<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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="#android:color/white"
app:tabGravity="fill"
app:tabMode="fixed"
app:tabSelectedTextColor="#color/colorPrimaryDark"
app:tabTextColor="#color/colorPrimary" />
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_search_white" />
</android.support.design.widget.CoordinatorLayout>
This is how I am changing back and forth between HomeTabFragment and SettingsFragment
public void onLeftDrawerSettingsClick(View view) {
mDrawerLayout.closeDrawer(Gravity.LEFT);
getSupportFragmentManager().beginTransaction().replace(R.id.tab_frag_container, mApp.getFragmentController().getSettingsFragment()).addToBackStack("Drawer").commit();
}
public void onLeftDrawerHomeClick(View view) {
mDrawerLayout.closeDrawer(Gravity.LEFT);
getSupportFragmentManager().beginTransaction().replace(R.id.tab_frag_container, mApp.getFragmentController().getHomeTabFragment()).commit();
}
I am unable to understand why the ViewPager is getting affected by the replace transaction. I found out that it has something to do with not allowing Child fragments in API Level 15 or lower, however this has been fixed in the latest support library and I don't think it can be an issue.
Is there any way I can replace the HomeTabFragment with SettingsFragment and vice-versa, without affecting the other functionalities? Or is it something I am doing wrong?

A quick solution was to not create the complete view of the fragment when it loads the second time. For that I put following code in the onCreateView() of HomeTabFragment
if (mParent != null)
return mParent;
// Inflate the layout for this fragment
mParent = inflater.inflate(R.layout.fragment_home_tab, container, false);
Though the solution works, but I am still unable to explain why is it happening? Posting it as an answer, in case someone is looking for a solution. Please provide a better solution with explanation, if you can.

Related

Getting blank space in tabbed activity fragment launch

This is my first fragment that is getting launched in the first tab. This fragment has a button clicking which I am supposed to launch this fragment with a new fragment. But while I do so the new fragment gets launched but there is a space on the top.
See the below picture:
In fact, the entire replaced fragment got slid down and went out of the screen below.
Those who are assuming that I have added a marginTop or paddingTop, to inform I have not added anything like that. In fact, if I replace the new fragment with some other fragment also the black space is still there on top. So it's not about the fragment with which I am replacing it.
Please help.
main_activity.xml
<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:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.moodoff.AllTabs">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="#FFC300"
app:tabIndicatorHeight="5dp"
android:background="#C70039"
app:tabGravity="fill"
/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="0dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
first_fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/allmoods"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:orientation="vertical"
android:background="#color/black"
tools:context="com.moodoff.Moods">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/firstRowOfMoods"
android:background="#color/black"
android:layout_weight="1"
android:layout_marginTop="5dp"
>
<!--- SOME BUTTONS --->
</LinearLayout>
</LinearLayout>

How to call a Class(Tabfragment.java) to another Fragment(DeliveryTab.java?

I created a Tabs one for Footer menu and another for just a fragment class inside this i have 3 Tabs.
I want to call Footer menu (Tabfragment.java)in another fragment(DeliveryTab.java).
I search it on google and revise the stackoverflow's question but none are helping me..
Here i post complete code.
activity_deliverytab.xml
<LinearLayout 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=".TabFragment"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs_delivery"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#color/tabMedium" />
<include
layout="#layout/tabfragment"></include>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager_delivery"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/white">
</android.support.v4.view.ViewPager>
</LinearLayout>
You should include Fragment in your layout using the fragment tag. Like this:
<LinearLayout 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=".TabFragment"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs_delivery"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#color/tabMedium" />
<android.support.v4.view.ViewPager
android:id="#+id/viewpager_delivery"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/white">
</android.support.v4.view.ViewPager>
<!-- Since you want it to be in the footer -->
<fragment android:name="xyz.xyz.xyz.TabFragment"
android:id="#+id/tabFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Hi i am not sure but you can try like this
inside DeliveryTab.java
ParentActivity activity = (ParentActivity) getActivity();
(ParentActivity is name of your activity which calls both TabsFragment and DeliveryTab )
Now get TabsFragment from FrameLayout or fragment whatever you set your TabsFragment like
((TabsFragment ) getSupportFragmentManager().findFragmentById(R.id.FragmentContainer))
How to add tag to Fragment see this -https://stackoverflow.com/a/23370128/4741746
Now you have TabsFragment now get ViewPager
mViewPager.setCurrentItem(getPosition);

Fragment with swipe-refresh Layout not transitioning

I have a fragment with a swipe-refresh layout containing a Recycler view and I added custom transitions and associated it with the fragment through frag.setEnterTransition() before the I started the fragment's transaction. But however it doesn't transition at all. It just abruptly appears, just as it would without transitions.
To narrow-down where I could have gone wrong, I redid it with a LinearLayout instead of swipeRefreshLayout and the fragment transitions as expected.
This is my xml for the fragment.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_refresh_layout_inapp_list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rv_inapp_messages_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="#dimen/transactions_space_small"/>
<include layout="#layout/widget_empty_screen"/>
</FrameLayout>
</android.support.v4.widget.SwipeRefreshLayout>
This is how the fragment gets transacted.
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
fragment.setEnterTransition(bottomGravitySlide);
fragment.setExitTransition(fadeOut);
fragment.setAllowEnterTransitionOverlap(false);
fragment.setAllowReturnTransitionOverlap(false);
}
fragmentTransaction.replace(R.id.vg_full_container, fragment, TAG_INTRODUCTION).commitAllowingStateLoss();
And I'm using API23, so the API check shouldn't be the problem.
Where am I going wrong? What should I do if I want to have swipeRefreshLayout and still be able to transition?
I wanted to programmatically move a floating action button to the top center by a transition within a SwipeRefreshLayout and encountered the same problem.
Encapsulating the SwipeRefreshLayout by a FrameLayout solved my issue.
Before:
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- some other views -->
<android.support.design.widget.FloatingActionButton
android:id="#+id/floating_action_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:src="#drawable/add"
android:tint="#android:color/white"
android:layout_margin="#dimen/pad16dp" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
After:
<FrameLayout
android:id="#+id/transitions_container"
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">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- some other views -->
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/floating_action_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:src="#drawable/add"
android:tint="#android:color/white"
android:layout_margin="#dimen/pad16dp" />
</FrameLayout>

Problems replacing an android fragment

What I have:
I am using the latest Android support and design libraries on API 22. I have a fragment called ProgressFragment which I only run when my app is first installed as follows:
mProgressFragment = new ProgressFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.main_container, mProgressFragment, TAG_TASK_FRAGMENT)
.commit();
This is the layout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/progress_frag"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
>
<ProgressBar
android:id="#+id/build_lib_progressbar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/progress_msg1"
android:layout_gravity="center"
android:textSize="22sp"
android:textColor="#color/text_primary"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/progress_msg2"
android:layout_gravity="center"
android:paddingTop="10dp"
android:textColor="#color/text_secondary"/>
</LinearLayout>
</LinearLayout>
This fragment contains an AsyncTask. When it completes, it is replaced by another fragment (called MainFragment) in MainActivity inside the AsyncTask callback onPostExecute() like so:
getSupportFragmentManager().beginTransaction()
.replace(R.id.main_container, new MainFragment())
.commit();
This is the MainFragment layout:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="#+id/main_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:id="#+id/main_appbar_layout"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<include layout="#layout/toolbar" />
<android.support.design.widget.TabLayout
android:id="#+id/main_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"
app:tabIndicatorHeight="4dp"
app:tabTextColor="#color/white"/>
</android.support.design.widget.AppBarLayout>
EDIT:
And this is MainActivity's layout:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Main content displayed here -->
<FrameLayout
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Navigation Drawer -->
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/nav_drawer_header"
app:menu="#menu/nav_view_menu"
android:background="#ffffff"
app:itemTextColor="#color/text_tertiary"
app:itemIconTint="#8b8b8b"
/>
The Problem:
When the AsyncTask in ProgressFragment completes and is replaced by MainFragment, the TabLayout view does not display tabs:
My application has 2 possible paths at startup. It either:
Adds the ProgressFragment (if first run) -> then replaced by MainFragment
Adds MainFragment otherwise (tabs show up fine here)
Both Fragment replacements happen in MainActivity.
The problem deals with path 1
EDIT 2:
Calling recreate() in MainActivity "fixes" this for now. Though I wouldn't call it a solution. Will come back to it later.
UPDATE: It was a bug on v22.2.1, solved on newer releases
Found the problem here: https://code.google.com/p/android/issues/detail?id=180462
Simple workaround:
tabLayout.post(new Runnable() {
#Override
public void run() {
tabLayout.setupWithViewPager(viewPager);
}
});

Should the CoordinatorLayout be placed in the Activity or the Fragment when dealing with both scrolling and non-scrolling fragments?

In the examples for CoordinatorLayout, it's always placed in the Activity, and the Fragments are all scrolling.
It's reasonable to imagine a scenario though where some of the fragments being loaded are scrollable and some of the fragments are not, but they get loaded in the same placeholder in the activity. In this scenario, should the CoordinatorLayout be placed in the Activity or in the Fragments?
On one hand, because you specify the Toolbar as a child of it, it seems that it should all be in the Activity.
On the other hand, if you have both scrolling and non-scrolling fragments loaded in the same placeholder, then this seems difficult to configure (e.g. what scrolling behaviour do you specify for the Fragment placeholder?), so it seems like it should live in the Fragment. In that case though, does each Fragment have to set the Toolbar again?
Q:should the CoordinatorLayout be placed in the Activity or in the Fragments?
A:You can use CoordinatorLayout in activity or fragment in different situation
Q:On one hand, because you specify the Toolbar as a child of it, it seems that it should all be in the Activity.
you can add toolbar to fragment layout instead of activity layout like below
in this example I create activity with NavigationView and viewPager :
so create layout for my activity(this layout is for MainActivity):
<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"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_height="match_parent"
android:layout_width="240dp"
android:layout_gravity="right"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/drawer_view"
app:itemIconTint="#color/tint_item_color"
app:itemTextColor="#color/tint_item_color"
/>
</android.support.v4.widget.DrawerLayout>
for create viewPager with tablayout I create this layout(this layout is for fragmentViewPager):
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<include layout="#layout/toolbar_main"
android:id="#+id/toolbar"/>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabIndicatorColor="#color/tab_color"
app:tabSelectedTextColor="#color/tab_color"
/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
then use another layout for listFragment that I use in viewPager :
<android.support.design.widget.CoordinatorLayout
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"
android:id="#+id/main_list_content"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="#color/background_window">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="0dp"
android:id="#+id/exersice_listviwe"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="16dp"
android:layout_marginBottom="64dp"
android:clickable="true"
android:src="#drawable/ic_done"
fab:layout_anchor="#+id/main_list_content"
fab:layout_anchorGravity="bottom|right"
/>
</android.support.design.widget.CoordinatorLayout >

Categories

Resources