I've been running into a strange problem with fragments inside a viewpager. If I rotate the device once, everything seems to work and my fragments load with all their data intact. However on a second rotation, the fragments inside my viewpager seem to disappear. If i check isAdded(), it returns true, however isVisible() returns false. Is there a reason why a fragment would be added to my viewpager, but not visible?
Here's my Fragment which contains the viewpager:
public class DrawerFragment extends ParentFragment{
ViewPager viewPager;
GradingFragmentPagerAdapter pagerAdapter;
ArrayList<ParentFragment> mGradingFragments;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
viewPager = (android.support.v4.view.ViewPager) rootView.findViewById(R.id.pager);
if(mFragments == null){
mFragments = new ArrayList<ParentFragment>();
mFragments.add(new FragmentA());
mFragments.add(new FragmentB());
}
pagerAdapter = new MyFragmentPager(getChildFragmentManager(), mFragments);
viewPager.setAdapter(pagerAdapter);
return rootView;
}
}
Here's my PagerAdapter class
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
ArrayList<ParentFragment > fragments;
public GradingFragmentPagerAdapter(android.support.v4.app.FragmentManager fm, ArrayList<ParentFragment> fragments){
super(fm);
this.fragments = fragments;
}
#Override
public ParentFragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
}
What i don't understand is that it only seems to break on the second rotation. If i set a background color on the viewpager, after 2 rotations, the area where my fragments should be are the viewpagers background color. However if i look at it in debug mode, the fragment's are added to the pagerAdapter. They just not visible.
Also it doesn't seem like onCreateView is getting called on the 2 fragments inside the viewpager. I'm not entirely sure if that's expected behavior or not when using setRetainInstance(true). From what I understand, setting it on the parent fragment should handle it's child fragments as well. But don't the child fragment's views still need to be recreated each rotation?
Related
How to add a listview inside a viewpager (without using fragments)? Could you please help me? Thanks in advance.
It will be easy if you use Fragment in ViewPager, BUT if you dont want to use ViewPager with Fragment than ViewPager Without Fragments is example where you add Views and layouts to ViewPager and is more complex.
A good example is an image gallery, where the user can swipe between different pictures. On these types of pages, all you really want to display is a view of static content (in this case, an image), how to utilize the ViewPager with just plain-old Views and layouts.
It will be best to use fragment for each pages of viewPager. In this way you will be able to maintain individual pages easily.
In your fragment class(a java class which extends Fragment) you can work with your listview like initializing,setting adapter to listview,setting onClickListner for listview items same as you do in Activity
You can't use ViewPager to swipe between Activities. You need to convert each of you Activities into Fragments, then combine everything in one FragmentActivity with the Adapter you use with ViewPager.
This is not how ViewPager works. You feed the pages to ViewPager with a PagerAdapter. Your ListView will be contained within a Fragment created by the PagerAdapter.
In the layout:
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/home_pannels_pager" />
In the FragmentActivity with this layout:
ViewPager pager = (ViewPager) findViewById(R.id.viewPager);
pager.setAdapter(new PagerAdapter(getSupportFragmentManager()));
Example of simle PagerAdapter:
public class PagerAdapter extends FragmentPagerAdapter {
public FrontPageAdapter(FragmentManager Fm) {
super(Fm);
}
#Override
public Fragment getItem(int position) {
Bundle arguments = new Bundle();
arguments.putInt("position", position);
FragmentPage fragment = new FragmentPage();
fragment.setArguments(arguments);
return fragment;
}
#Override
public int getCount() {
// return count of pages
return 3;
}
}
Example of FragmentPage:
public class FragmentPage extends Fragment {
public FragmentPage() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_frontpage, container, false);
// probably cast to ViewGroup and find your ListView
Bundle arguments = getArguments();
int position = b.getInt("position");
return view;
}
}
Answered here - https://stackoverflow.com/a/28798795/7764015
I am new in view pager.i have 2 pages in view pager..each contain button..i want show button after page fully loaded.Now button is showing half scrolling it self..
class MyPageAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MyPageAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
public int getItemPosition(Object object) {
return POSITION_NONE;
}
adding page
pageAdapter = new MyPageAdapter(activity.getSupportFragmentManager(), fragments);
viewpager.setId(position);
viewpager.setAdapter(pageAdapter);
fragment:
public class secondclass extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_secondclass, container, false);
return rootView;
}
please help me..
Just use OnPageChangeListener.
Actually you need to do some tedious tasks for this to be done.
First your activity containing the viewpager should have a way to communicate with the fragments of the viewpager. once you are done with this.
Then set OnPageChangeListener on the viewpager
and one of the overridden callback methods would be the following one
#Override
public void onPageSelected(int position) {
// you know the position now. send the message to the fragment at this position to show the button or do any particular task
}
you are all set to go
In viewpager nearby fragments are loaded even before they are actually visible to the user, this is done so as to provide a smooth scrolling effect.
So onCreateView and onResume methods of the second fragment is already called...even before the user scrolls to the second page.
So to do something exactly when the user loads a page completely we need to user the onPageSelected method and with the help of the position argument we notify the fragment at that position to do the tasks.
In your case show the button...so you need to set visibility of the button INVISIBLE in the layout and make it visible when the page is selected.
For the above thing to work your activity needs to have a reference to the fragment...or you may request the viewpageradapter to provide you the reference by doing a bit caching of the current fragment...apply any logic of yours.
Assume all your fragments are of type MyFragment and have a method doVisibleTask to make the button visible AND getItem of your view pager adapter returns the same instance everytime for a particular position.
you could do the following
#Override
public void onPageSelected(int position) {
// get the reference to the fragment
MyFragment mf = (MyFragment)viewPagerAdapter.getItem(position);
mf.m=doVisibleTask();
// you know the position now. send the message to the fragment at this position to show the button or do any particular task
}
I am having problems with fragments or maybe rather the way I want them to work.
In my activity I have a layout container (R.id.container1) to which I add a fragment (FragMain) programmatically at startup.
In the fragment I have 2 Fragments (Frag1, Frag2) and a ViewPager which loads several other fragments (FragA, FragB, FragC, FragD, FragE) via a FragmentPagerAdapter.
On a button press I replace the whole content of R.id.container1, so FragMain is replaced with another Fragment (FragSub).
Now when I press the back button, FragMain is loaded again, but the ViewPager isn't fully initialized, some Fragments are missing. From what I observed, it's always FragB and FragD missing, If I scroll to the empty views, the app crashes. The other fragments seem to be fine. What's going wrong here?
This thread suggests using getChildFragmentManager in creation of the PagerAdapter, but I am already doing that... Fragment in ViewPager not restored after popBackStack
I am accessing the fragments via e.g.
((FragA)((PagerAdapter)viewPager.getAdapter()).getItem(0));
Is this the best way?
Some Code :
MainActivity's onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pagerFragList = new Vector<Fragment>();
pagerFragList.add(Fragment.instantiate(this, FragA.class.getName()));
pagerFragList.add(Fragment.instantiate(this, FragB.class.getName()));
pagerFragList.add(Fragment.instantiate(this, FragC.class.getName()));
pagerFragList.add(Fragment.instantiate(this, FragD.class.getName()));
pagerFragList.add(Fragment.instantiate(this, FragE.class.getName()));
FragMain fragMain = (FragMain)getSupportFragmentManager().findFragmentByTag(FragMain.debugTag);
if(fragMain==null) fragMain = new FragMain();
FragmentHelper.replaceSupportFragment(this, fragMain, R.id.container1, false, FragMain);
}
Helper
public Vector<Fragment> getFragList() {
return pagerFragList;
}
FragMain's onViewCreated
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
pagerAdapter = new PagerAdapter(getChildFragmentManager(), ((MainActivity)getActivity()).getFragList());
viewPager = ((ViewPager)view.findViewById(R.id.viewPager));
viewPager.setAdapter(pagerAdapter);
viewPager.setOffscreenPageLimit(5);
viewPager.setCurrentItem(0, true);
}
The PagerAdapter
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments=fragments;
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
}
Have no idea why this seems to be fixing it on my end, but try commenting out your "viewPager.setOffscreenPageLimit(5);" line.
I'm still investigating and will be back with more if I find anything else useful out.
The other thing it turns out that I had to do was override the "state" methods of a FragmentStatePagerAdapter like this:
#Override
public Parcelable saveState() {
return null;
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
//do nothing
}
In order to bypass whatever strange thing that was causing problems (must have had something to do with saving and restoring the states of nested fragments in a ViewPager...
There are alot of permutations involving the state of fragments and backstack transitions. For debug, it may help to isolate the event you are working with (backbutton , orientation change ... ) and to look at the following before and after your event....
state of fragment manager which includes the backstack i believe...
//debug
getFragmentManager().dump("", null,
new PrintWriter(System.out, true), null);
see this thread
Need some help with my problem of updating pages while using viewpager. I am using a simple viewpager with FragmentStatePagerAdapter. All I want to do is get access to the current fragment/view so as I can update some textviews in my fragment/view. I searched around in the forum and came to know few things
- One of the ways to handle this is by setting tag in instantiateItem() call back of the adapter and retreive the view by findViewbyTag. I could not understand how to implement this and I am also not sure if that will work for FragmentStatePagerAdapter.
- I explored other options as suggested in various forums, but cannot make them work.
My code is very much same as in a android http://developer.android.com/training/animation/screen-slide.html. Basic components are the same (Fragment activity xml with some display components including a textview, viewpager xml with just a view pager in it, a Fragment class and the main FragmentActivity class). in my FragmentActivity class I have added a pageChangelistener to my viewpager so as I can do my textview changes during onPageSelected().
Any help is is appreciated.
Adding the code for reference.
Public class myActivity extends FragmentActivity
//Variable declarations
protected void onCreate(Bundle savedInstanceState) {
ViewPager mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
View CurrView;
OnPageChangeListener pageChangelistener = new OnPageChangeListener() {
#Override
public void onPageSelected(int pageSelected) {
doTextViewChnges();//access the text view and update it based on pageSelected
---THIS IS WHERE I AM STUCK IN TRYING TO GET THE TEXTVIEW IN MY CURRENT FRAGMWNT/VIEW-------
}
mPager.setOnPageChangeListener(pageChangelistener);
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
return ScreenSlidePageFragment.create(position, <other parameters I want to pass>);
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
in your OnPageChangeListener:
OnPageChangeListener pageChangelistener = new OnPageChangeListener() {
#Override
public void onPageSelected(int pageSelected) {
ScreenSlidePageFragment currentFragment = (ScreenSlidePageFragment) mPagerAdapter.getItem(pageSelected)
doTextViewChnges();//access the text view and update it based on pageSelected
---THIS IS WHERE I AM STUCK IN TRYING TO GET THE TEXTVIEW IN MY CURRENT FRAGMWNT/VIEW-------
}
i assume you want to access your fragments from your activity and update the views.Fragments are parts of activities and their views can be accessed by them. Fragments are created dynamically in viewadapters and there is no straight forward and easy way to Tag them. You may simply access a fragment by its index number.first one is 0 second one is 1 and so on...
//access your fragment(in your case your first fragment)
//this part should be inside your doTextViewChnges()
Fragment fragment = (Fragment ) adapterViewPager
.getFragment(0);
if (fragment != null) {
//call a public method inside your fragment to update your text view
fragment .updateYourTextView();
}
Edit: inside your fragment create the following method and update your textview from there.
void updateYourTextView() {
yourTextView.setText("yourtext");
}
In my application i have a tabhost with a tabwidget that have several Tabs.
Now i need a tab that show me inside the tabcontent a schedule grid that allow swipe to right and left to move through the months. But i need that the tab stay fixes and only the schedule swipes.
The navigation type (Fixed tabs + Swipe) allow me that? From what I understand this navigation allow the swipe but the tab don't stay the same.
What i need is possible?
Thanks for your help and attention.
I would say possible, stay with your codes on tabhost and tabwidget.
So I would assume one of those tabs are calling an Activity which probably named Schedule.class, by default tabhost does not allow any swiping to change tab feature, that is fine.
So in your Schedule Activity, you would be using ViewPager, I learnt how to use it from this article: http://thepseudocoder.wordpress.com/2011/10/05/android-page-swiping-using-viewpager/
Which is pretty easy to be understood. You may try to use it, hope I answered your question
Update: Here's a sample
Schedule.class
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.schedule);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
List<Fragment> fragments = new ArrayList<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName()));
fragments.add(Fragment.instantiate(this, Fragment2.class.getName()));
fragments.add(Fragment.instantiate(this, Fragment3.class.getName()));
MyFragmentAdapter miscFragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(), fragments);
viewPager.setAdapter(miscFragmentAdapter);
}
MyFragmentAdapter.class
public class MyFragmentAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MiscFragmentAdapter(FragmentManager fragmentManager, List<Fragment> fragments) {
super(fragmentManager);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
}
schedule.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
Fragment1.class or Fragment2.class or Fragment3.class
public class Fragment1 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
return (LinearLayout) inflater.inflate(R.layout.fragment1, container, false);
}
}
fragment1 is a simple layout with whatever you want inside it.