I want to get the last fragment in the backstack, or the current displayed it's the same for me, in the tab b_1
. As you can see in the following image, I have a ViewPager, and another one inner tab b
. Thus there are four current fragments displayed.
Question: How can I get the Fragment 2
instance?
I have seen another solutions, but none works for this scenario.
Annotation: The fragment to return is not necessary the hosted in the ViewPager. I can have opened two more fragments in a tab.
With this method I get all the current visible fragments, but not the one specific I want.
public ArrayList<Fragment> getVisibleFragment() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
ArrayList<Fragment> visibleFragments = new ArrayList<>();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment != null && fragment.isVisible())
visibleFragments.add(fragment);
}
}
return visibleFragments;
}
Some interesting code
activity_main.xml
<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/activity_main"
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.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"/>
</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>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static ViewPagerAdapter adapter;
private static ViewPager viewPager;
private TabLayout tabLayout;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager();
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
setupTabIcons();
}
private void setupViewPager() {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
// Wrap with HostFragment to get separate tabbed nagivation.
adapter.addFrag(HostFragment.newInstance(new Fragment1()), null);
adapter.addFrag(HostFragment.newInstance(new RootFragment2()), null);
adapter.addFrag(HostFragment.newInstance(new Fragment4()), null);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(2);
}
public void openNewFragment(Fragment fragment) {
HostFragment hostFragment = (HostFragment) adapter.getItem(viewPager.getCurrentItem());
hostFragment.replaceFragment(fragment, true);
}
}
fragment_host.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/hosted_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
HostFragment.java
/**
* This class implements separate navigation for a tabbed viewpager.
*
* Based on https://medium.com/@nilan/separate-back-navigation-for-
* a-tabbed-view-pager-in-android-459859f607e4#.u96of4m4x
*/
public class HostFragment extends BackStackFragment {
private Fragment fragment;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_host, container, false);
if (fragment != null) {
replaceFragment(fragment, false);
}
return view;
}
public void replaceFragment(Fragment fragment, boolean addToBackstack) {
if (addToBackstack) {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit();
} else {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit();
}
}
public static HostFragment newInstance(Fragment fragment) {
HostFragment hostFragment = new HostFragment();
hostFragment.fragment = fragment;
return hostFragment;
}
public Fragment getFragment() {
return fragment;
}
}
fragment2_root.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fragment2_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tab2_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"/>
<android.support.v4.view.ViewPager
android:id="@+id/tab2_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</LinearLayout>
RootFragment2.java
public class RootFragment2 extends Fragment {
private ViewPagerAdapter adapter;
private ViewPager viewPager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the layout for this fragment.
View root = inflater.inflate(R.layout.fragment2_root, container, false);
viewPager = (ViewPager) root.findViewById(R.id.tab2_viewpager);
setupViewPager(viewPager);
TabLayout tabLayout = (TabLayout) root.findViewById(R.id.tab2_tabs);
tabLayout.setupWithViewPager(viewPager);
return root;
}
private void setupViewPager(ViewPager viewPager) {
adapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager());
// Wrap with HostFragment to get separate tabbed nagivation.
adapter.addFrag(HostFragment.newInstance(new Fragment2()), null);
adapter.addFrag(HostFragment.newInstance(new Fragment3()), null);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(1);
}
public ViewPagerAdapter getAdapter() {
return adapter;
}
public ViewPager getViewPager() {
return viewPager;
}
}
First define a
SparseArray
in yourViewPagers
' adapters like below. In this array we'll hold the instance of fragments.And Override your Adapters'
instantiateItem
method.Also Override
destroyItem
method of yourViewPagers
And define a new method to get your
ViewPager
Fragments
instance.And finally set add a
PageChangeListener
to yourViewPagers
:I hope this'll help you. Good luck.
Edit: I'm sorry i cannot understand exactly what you're planning to do but if you need to keep sub fragment (b_1, b_2) instance you can define a method to your activity such as
and in your sub view pager's adapter you can call this method like below:
With this way you can keep one instance and your top fragment.
After some comments with DEADMC, I decided to implement it with extra memory, saving in a list the open fragments.
I explain my solution. I hve two types of special fragments, host and root. Host Fragments are those which are the init of a tab. Root Fragments are those which hold a ViewPager. In this scenario,
tab_b
has a Root Fragment with an inner ViewPager.For each tab, this is, for each HostFragment, I have added a list
fragments
to save the fragments opened in this tab. Also a methodgetCurrentFragment
to get the last displayed in this tab.Also a method to remove the last fragment displayed in this tab is needed, to maintain a true state. Back button needs to be redirect to this method.
Also previous methods need to be changed, to insert the new fragments opened into the list.
RootFragment is an interface implemented by those fragments which holds a ViewPager.
And then, the implementation would be:
MainActivity is not a Fragment, but I implement RootFragment interface for meaning.
and RootFragment2
And then, I just need to call:
I would do something like that:
1. Create a interface like this.
2. All fragments inside ViewPagers should implements this one.
3. Add
OnPageChangeListener
to your main VP. So You will always know current position.4. Add
OnPageChangeListener
your inner(s) VP so you will know which one is there on screen.5. Add method to your adapter (both main and inner) which returns your fragment from list passed to it.
6. All Fragments should return this in
returnMyself()
7. Fragment that has inner fragments should return in returnMyself something like.
8. From main fragment/activity you just call.
And you got your current fragment.
You can create something like
CustomFragment
class which containsgetClassName
method and extends fromFragment
class. Then extend all your fragments such asRootFragment2
fromCustomFragment
class instead of justFragment
.So you can get fragment like this: