I have an Android App with a single activity. The activity contains a SlidingTabLayout with a ViewPageAdapter as in this example. Each tab contains a respective root fragment which I then replace with other fragments as the user uses that screen. A visual representation is shown below:
With my current implementation I do the following: go to tab1, the ProductListFragment immediately loads by replacing the ProductRootFragment with the ProductListFragment. I click on a product and it replaces the ProductListFragment with the ProductDetailFragment. Now I switch to tab2 and Tab2ListFragment immediately loads by replacing Tab2RootFragment. I click on an item and the Tab2DetailFragment replaces the Tab2ListFragment. I now return to Tab1 and, as I expect, ProductDetailFragment is still displayed. However, if I now click the back button, it doesn't take me back to ProductListFragment as I expect. Instead it pops off Tab2DetailFragment from the backstack.
I want to implement a separate backstack for each "tab" fragment. There are several posts about this already but they all seem to be outdated and some suggest very elaborate solutions. (See here, here and here...)
It seems that in the latest versions of the SDK Android can automatically handle this backstack hierarchy without the need to manually implement some kind of backstack by using getChildFragmentManager rather than getSupportFragmentManager in my transactions where I replace the fragments. I have, however, not been able to get this to work. (I intuitively feel that the correct solution lies along the lines of letting Android handle this as it feels like manually overriding the back button and implementing your own stack is an elaborate hack.)
Can someone please explain how to properly implement the expected behavior where a separate backstack is maintained for each tab? Or perhaps link to a simple, well-designed and up-to-date example of how to achieve the desired behavior?
Additional information about my code: In my MainActivity.java, I construct the ViewPagerAdapter using getSupportFragmentManager().
ViewPagerAdapter.java
@Override
public Fragment getItem(int position) {
switch(position){
case 0: return new ProductRootFragment();
...
}
...
}
ProductRootFragment.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.product_root_fragment, container, false);
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
transaction.replace(R.id.product_root_container, new ProductListFragment());
transaction.commit();
return view;
}
ProductListFragment.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.product_list_fragment, container, false);
view = (ProductListView) layout;
return view;
}
...
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
...
ProductDetailFragment newFragment = new ProductDetailFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.product_root_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
ProductDetailFragment.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = (ProductDetailView) inflater.inflate(R.layout.product_detail_fragment, container, false);
return view;
}
ViewPager2 is an improved version of the ViewPager library that offers enhanced functionality and addresses common difficulties with using ViewPager . If your app already uses ViewPager , read this page to learn more about migrating to ViewPager2 .
ViewPager in Android allows the user to flip left and right through pages of data. In our android ViewPager application we'll implement a ViewPager that swipes through three views with different images and texts.
PageTransformer interface and supply it to the view pager. The interface exposes a single method, transformPage() . At each point in the screen's transition, this method is called once for each visible page (generally there's only one visible page) and for adjacent pages just off the screen.
I know its late to answer this question, but maybe someone still need it.
For achieve this you must use getChildFragmentManager()
instead of getFragmentManager()
in your root fragments
For example I have a activity with ViewPager and TabLayout and I add
RootFragment1
and RootFragment2
to ViewPager and setup TabLayout with ViewPager.
Now in my RootFragment1
for replace my Tab1Fragment1
I use this code:
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.RootFrame1, Tab1Fragment1.newInstance(), "MyTag");
ft.commit();
And need the method to popup fragment from backstack likes this:
public boolean popBackStack() {
if(getChildFragmentManager().getBackStackEntryCount() > 0) {
getChildFragmentManager().popBackStackImmediate();
return true;
} else
return false;
}
And for example I have a button in the Tab1Fragment1
that replace fragment Tab1Fragment2
with current. The button onClickListener must look likes this:
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.RootFrame1, Tab1Fragment2.newInstance(), "MyTag");
ft.addToBackStack(null);
ft.commit();
}
});
I do same with second fragment (RootFragment2
).
After that, now I only need to override onBackPressed()
of my MainActivity
likes below:
@Override
public void onBackPressed() {
if (viewPager.getCurrentItem() == 0) {
RootFragment1 fragment = ((RootFragment1) sectionsPagerAdapter.getItem(0));
if (!fragment.popBackStack())
super.onBackPressed();
} else if (viewPager.getCurrentItem() == 1) {
RootFragment2 fragment = ((RootFragment2) sectionsPagerAdapter.getItem(1));
if (!fragment.popBackStack())
super.onBackPressed();
} else
super.onBackPressed();
}
That I check if each tab contains fragment then I popup from its backstack else call super.onBackPressed()
to do default action.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With