Android ViewPager Inside Fragment Loaded Only Once - android

I am getting issue with ViewPager. I am using FragmentActivity and I added the multiple fragment inside FragmentActivity as following method.
public void addFragment(Fragment fragment, boolean addToBackStack, int transition) {
FragmentTransaction ft = getFragmentManager().beginTransaction().setCustomAnimations(R.anim.slide_up,R.anim.slide_down,R.anim.slide_up,R.anim.slide_down);
ft.replace(R.id.main, fragment);
ft.setTransition(transition);
if (addToBackStack)
ft.addToBackStack(null);
ft.commit();
}
I am using ViewPager Inside the fragment. ViewPager is working fine when FragmentActivity loaded. but when i use another fragment ViewPager got invisible.
for example
a.) Fragment A with ViewPager
b.) Fragment B without ViewPager
Fragment A working fine when I run App. when i go to Fragment B
then I again i replace Fragment B to Fragment A then ViewPager is not working. I see the blank view where I am using ViewPager.
Please let me know How can i solve this issue
Thanks

I solved it myself the issue was when you use the ViewPager inside the fragment use getChildFragmentManager() instead of getSupportFragmentManager() or getFragmentManager().
That's it.

I cannot comment so I'm going to write an answer here.
Why you don't just put the viewpager as a fragment:
public class ViewPager extends Fragment{
public static final String TAG = ViewPager.class.getSimpleName();
private ViewPagerAdapter mAdapter;
public static ViewPager newinstance(){
ViewPager viewPager = new ViewPager();
return viewPager ;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_pager, container, false);
ViewPager viewPager = (ViewPager) view.findViewById(R.id.pager);
mAdapter = new ViewPagerAdapter(getChildFragmentManager());
viewPager.setAdapter(mAdapter);
return view;
}
}
In your adapter:
public class ViewPagerAdapter extends FragmentPagerAdapter{
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
return Fragment.newinstance();
}
#Override
public int getCount() {
return 5; //number of pages on your viewPager
}
Then on your main activity you can make the transaction to add the view pager
ViewPager viewPager = ViewPager.newInstance();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.content_frame,viewPager);
ft.addToBackStack(ViewPager.TAG);
ft.commit();

Related

Change Title TextView when call one fragment to another fragment

I am working on the application in which I added a Navigation Drawer with Tabs. So, for the Navigation Drawer menu option I create a fragment for each option and it works well...
In my main Activity I inflate my TabFragment (contains fragment_1, or fragment_2) as UI, and on the Fragment_1 there is one Button and when I click the button I want to open the Navigation Drawer fragment....
My Navigation Drawer fragment opens fine, but the problem is when my Navigation drawer fragment is open my titleBar doesn't change as per the fragment title...
Note: I know when we open a fragment we have to replace the fragment View to the new fragment View but I want to open a Fragment as an Activity
Picture1: When I click on Button the Second Picture appears, but I want to change the TitleView and remove the Navigation drawer icon.
Edit
In my MainActivity, I inflate Tabfragment as
mFragmentTransaction=mFragmentManager.beginTransaction();
mFragmentTransaction.replace(R.id.containerView, new TabFragment()).commit();
MyTabFragment :
public class TabFragment extends Fragment {
public TabFragment() {
// Required empty public constructor
}
public static TabLayout tabLayout;
public static ViewPager viewPager;
public static int int_items = 2 ;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View x=inflater.inflate(R.layout.content_main_menu,null);
tabLayout=(TabLayout) x.findViewById(R.id.tabs);
viewPager =(ViewPager) x.findViewById(R.id.viewpager);
viewPager.setAdapter(new MyAdapter(getChildFragmentManager()));
tabLayout.post(new Runnable() {
#Override
public void run() {
tabLayout.setupWithViewPager(viewPager);
}
});
return x;
}
class MyAdapter extends FragmentPagerAdapter{
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new HomeFragment();
case 1:
return new Offers();
}
return null;
}
#Override
public int getCount() {
return int_items;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0 :
return "Home";
case 1:
return "Offers";
}
return null;
}
}
}
On Button click in HomeFragment(or fragment_1)
Fragment fragment = new NavigationDrawerFragment();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
I just find my Question's Answer..
Before i tried to call fragment to fragment class that's why my ContainerView Remains same in the NavigationDrawer Fragment. So Now this time, I am Creating a new Activity and in this Activity I inflate the navigation Drawer fragment, due to this my previous ContainerView is Replaced by the New Activity layout

Replacing Fragment in a Tablayout

I'm trying to replace a fragment in my Tablayout with a new Fragment, however everywhere i have looked uses:
Fragment newFragment = new UserProfileFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
However, as i'm using tablayout and viewpager, i don't have anything like R.id.fragment_container. Below is my activity which the fragments are attached too.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_home);
userHomeToolbar = (Toolbar) findViewById(R.id.userHomeTabView);
setSupportActionBar(userHomeToolbar);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new UserProfileFragment(), "Home");
adapter.addFragment(new FootballGroundFragment(), "Grounds");
adapter.addFragment(new UserSettingsFragment(), "Friends");
viewPager.setAdapter(adapter);
}
public void onFragmentInteraction(Uri uri){
//you can leave it empty
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Your situation is replace a fragment in a viewpager, there have been many good solutions for it, check:
1) Replace Fragment inside a ViewPager
or Replace one Fragment with another in ViewPager
or Replace current Fragment in ViewPager on Android
2) Here is a good tutorial:
http://www.pineappslab.com/post/fragments-viewpager/
You can create a container in the fragment you want to have multiple fragments. For this you can either use fragment tag or Frame Layout in your xml.
Some what like this.
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
And in your fragment you can inflate them using fragment transaction. Note that in your fragment you have to use childFragmentManager.
For example
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
ChildFragment fragB = new ChildFragment ();
childFragTrans.add(R.id.FRAGMENT_PLACEHOLDER, fragB);
childFragTrans.addToBackStack("B");
childFragTrans.commit();
By default FragmentPagerAdapter calls the getItem() method when there is no fragment associated with the given position. Therefore when you change the fragment at that position it is not updated. So one possible solution is to remove the old fragment present at that position from the fragment manager explicitly so that next time it adds the new fragment for that position.
It can be done like this:
Override the instantiateItem() method inside your ViewPagerAdapter class.
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
Fragment currentFragment = (Fragment) super.instantiateItem(container, position);
Fragment actualFragment = getItem(position);
if (actualFragment != currentFragment) {
// Remove the old fragment
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.remove(currentFragment);
transaction.commitNow();
// The super class method takes care of adding the new fragment
currentFragment = (Fragment) super.instantiateItem(container, position);
}
return currentFragment;
}

How to get the current fragment displayed in a specific tab of a viewpager?

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 your ViewPagers' adapters like below. In this array we'll hold the instance of fragments.
SparseArray<Fragment> registeredFragments = new SparseArray<>();
And Override your Adapters' instantiateItem method.
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
Also Override destroyItem method of your ViewPagers
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
And define a new method to get your ViewPager Fragments instance.
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
And finally set add a PageChangeListener to your ViewPagers:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// Here's your instance
YourFragment fragment =(YourFragment)yourPagerAdapter.getRegisteredFragment(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
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
public void setCurrentFragment(Fragment fragment){
this.currentFragment = fragment;
}
and in your sub view pager's adapter you can call this method like below:
subViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// Here's your instance
YourFragment fragment =(YourFragment)yourSubPagerAdapter.getRegisteredFragment(position);
((MyActivity)getActivity).setCurrentFragment(fragment);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
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 method getCurrentFragment to get the last displayed in this tab.
public class HostFragment extends BackStackFragment {
private ArrayList<Fragment> fragments = new ArrayList<>();
public Fragment getCurrentFragment() {
return fragments.get(fragments.size() - 1);
}
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.
public void removeCurrentFragment() {
getChildFragmentManager().popBackStack();
fragments.remove(fragments.size() - 1);
}
Also previous methods need to be changed, to insert the new fragments opened into the list.
public void replaceFragment(Fragment fragment, boolean addToBackstack) {
// NEW: Add new fragment to the list.
fragments.add(fragment);
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();
// NEW: Add first fragment to the list.
hostFragment.fragments.add(fragment);
return hostFragment;
}
} // HostFragment.
RootFragment is an interface implemented by those fragments which holds a ViewPager.
public interface RootFragment {
/**
* Opens a new Fragment in the current page of the ViewPager held by this Fragment.
*
* #param fragment - new Fragment to be opened.
*/
void openNewFragment(Fragment fragment);
/**
* Returns the fragment displayed in the current tab of the ViewPager held by this Fragment.
*/
Fragment getCurrentFragment();
}
And then, the implementation would be:
MainActivity is not a Fragment, but I implement RootFragment interface for meaning.
public class MainActivity extends AppCompatActivity implements RootFragment {
private void setupViewPager() {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
// Wrap with HostFragment to get separate tabbed nagivation.
adapter.addFrag(HostFragment.newInstance(new Fragment1()), null);
adapter.addFrag(new RootFragment2(), null); // This is a Root, not a Host.
adapter.addFrag(HostFragment.newInstance(new Fragment4()), null);
viewPager.setAdapter(adapter);
// 2 because TabLayout has 3 tabs.
viewPager.setOffscreenPageLimit(2);
}
#Override
public void openNewFragment(Fragment fragment) {
Fragment hosted = adapter.getItem(viewPager.getCurrentItem());
// Replace the fragment of current tab to [fragment].
if (hosted instanceof HostFragment) {
((HostFragment) hosted).replaceFragment(fragment, true);
// Spread action to next ViewPager.
} else {
((RootFragment) hosted).openNewFragment(fragment);
}
}
#Override
public Fragment getCurrentFragment() {
Fragment hosted = adapter.getItem(viewPager.getCurrentItem());
// Return current tab's fragment.
if (hosted instanceof HostFragment) {
return ((HostFragment) hosted).getCurrentFragment();
// Spread action to next ViewPager.
} else {
return ((RootFragment) hosted).getCurrentFragment();
}
}
}
and RootFragment2
public class RootFragment2 extends Fragment implements RootFragment {
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);
// 1 because TabLayout has 2 tabs.
viewPager.setOffscreenPageLimit(1);
}
#Override
public void openNewFragment(Fragment fragment) {
((HostFragment) adapter.getItem(viewPager.getCurrentItem())).replaceFragment(fragment, true);
}
#Override
public Fragment getCurrentFragment() {
return ((HostFragment) adapter.getItem(viewPager.getCurrentItem())).getCurrentFragment();
}
}
And then, I just need to call:
((MainActivity) getActivity()).getCurrentFragment();
You can create something like CustomFragment class which contains getClassName method and extends from Fragment class. Then extend all your fragments such as RootFragment2 from CustomFragment class instead of just Fragment.
So you can get fragment like this:
public CustomFragment getNeededFragment(String fragmentName) {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
CustomFragment result = null;
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment != null && fragment.isVisible()) {
try {
CustomFragment customFragment = (CustomFragment) customFragment;
if (customFragment.getClassName().equals(fragmentName)))
result = customFragment;
} catch (ClassCastException e) {
}
}
}
}
return result ;
}
I would do something like that:
1. Create a interface like this.
public interface ReturnMyself {
Fragment returnMyself();
}
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.
public ReturnMyself getReturnMyselfAtPosition()
6. All Fragments should return this in returnMyself()
7. Fragment that has inner fragments should return in returnMyself something like.
Fragment returnMyself() {
return this.myInnerFragmentAdapter.getReturnMyselfAtPosition().returnMyself();
}
8. From main fragment/activity you just call.
this.adapter.getReturnMyselfAtPosition().returnMyself();
And you got your current fragment.

How to delete fragments related to FragmentStatePagerAdapter by deleting the parent fragment

I have a TabsFragment, that is used to display FragmentStatePagerAdapter. To display tabs, I firstly create a TabsFragment, which creates multiple fragments, stored in tabs. The problem is, when I destroy a TabsFragment and create a new one, tab fragments created by previous TabsFragment are kept in memory for some reason. So does look like my TabsFragment class:
public class TabsFragment extends AbstractFragment {
public static final String TAG = "Tabs_Fragment";
private ViewPagerParallax viewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_tabs, container, false);
viewPager = (ViewPagerParallax)view.findViewById(R.id.viewpager);
viewPager.set_max_pages(CustomFragmentPagerAdapter.PAGE_COUNT);
viewPager.setBackgroundAsset(R.drawable.background);
viewPager.setAdapter(new CustomFragmentPagerAdapter(getFragmentManager()));
PagerSlidingTabStrip tabsStrip = (PagerSlidingTabStrip) view.findViewById(R.id.tabs);
tabsStrip.setViewPager(viewPager);
return view;
}
...
}
Like this I replace my TabsFragment with some other fragment:
public void transactOver(AbstractFragment what, int direction) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_content, what, what.getClassTag());
ft.commit();
}
Where R.id.fragment_content is a framelayout, that stores my fragmens. CustomFragmentPagerAdapter is coded as usual.
Finished up changing
viewPager.setAdapter(new CustomFragmentPagerAdapter(getFragmentManager()));
with
viewPager.setAdapter(new CustomFragmentPagerAdapter(getChildFragmentManager()));

Android tabs implemented with Fragments and ViewPager

My application has 3 tabs, each represented by Fragments. There is a custom FragmentPagerAdapter which also implements ActionBar.TabListener. Initially my FragmentPagerAdapter was returning new instances of fragments in public Fragment getItem(int index) method. Also, my TabListener implementation was instantiating Fragments and showing/hiding them in the onTabSelected/onTabUnselected. Unfortunately this approach doesn't fit me well, because in this case each Fragment is actually created twice. What I want is to create it once and then just hide/show, when necessary.
For that I have instantiated my fragment earlier in the activity and passed them to the PagerAdapter:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tabs_layout);
List<Fragment> fragments = initTabFragments();
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final ActionBar actionBar = getSupportActionBar();
TabsPagerAdapter pagerAdapter = new TabsPagerAdapter(this, getSupportFragmentManager(), fragments, viewPager);
viewPager.setAdapter(pagerAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (int tab_name : tabs) {
Tab tab = actionBar.newTab();
actionBar.addTab(tab.setText(tab_name).setTabListener(pagerAdapter));
}
...
}
private List<Fragment> initTabFragments() {
List<Fragment> fragments = new ArrayList<Fragment>(3);
fragments.add(SherlockFragment.instantiate(this, TabFragment1.class.getName()));
fragments.add(SherlockFragment.instantiate(this, TabFragment2.class.getName()));
fragments.add(SherlockFragment.instantiate(this, TabFragment3.class.getName()));
return fragments;
}
Then in the PagerAdapter I just return fragment:
#Override
public Fragment getItem(int index) {
return fragments.get(index);
}
To handle Tab selection there is the following code:
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
int position = tab.getPosition();
String tag = "android:switcher:" + viewPagerId + ":" + position;
Fragment fragment = context.getSupportFragmentManager().findFragmentByTag(tag);
switch (position) {
case 0:
if (fragment == null) {
ft.add(viewPagerId, fragments.get(0), tag);
} else {
// If it exists, simply attach it in order to show it
ft.show(fragments.get(0));
}
break;
}
case 1:
if (fragment == null) {
ft.add(viewPagerId, fragments.get(1), tag);
} else {
// If it exists, simply attach it in order to show it
ft.show(fragments.get(1));
}
break;
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
switch (tab.getPosition()) {
case 0:
ft.hide(fragments.get(0));
break;
case 1:
ft.hide(fragments.get(1));
break;
}
}
In this case each fragment is instantiated once. And the first tab is shown correctly, but when I switch between tabs second and third tabs are empty (just white background). Why?
I was trying to add fragment to a container android.R.id.content, but exception was thrown: Can't change container ID of fragment.... I found out that it is because when Fragment is returned in getItem method it is added to a viewPager container. That why I use viewPagerId when add fragment to a transaction.
Any help would be greatly appreciated.
Have a ExampleFragment class defined that extends Fragment. Something like shown below
public class ExampleFragment extends Fragment {
private View categoryView;
private ViewPager mViewPager;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
categoryView = inflater.inflate(R.layout.viewpager, container, false);
mViewPager = (ViewPager) categoryView.findViewById(R.id.pager);
return categoryView;
}
public ViewPager returnViewPager() {
return mViewPager;
}
}
main_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
tools:context=".ExampleFragmentActivity" >
<fragment
android:id="#+id/main_fragment"
android:name="somepackage.ExampleFragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
And then add this in the onCreate() of ExampleFragmentActivity
ExampleFragment fragment = (ExampleFragment) getSupportFragmentManager().findFragmentById(R.id.main_fragment);
mViewPager = fragment.returnViewPager();
fragmentManager = getSupportFragmentManager();

Categories

Resources