I implemented view pager in my activity like :
class MainActivity extends FragmentActivity implements
ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "FIRST", "SECOND", "THIRD" };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
// Initilization
viewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
getActionBar().setHomeButtonEnabled(false);
getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
getActionBar().addTab(getActionBar().newTab().setText(tab_name)
.setTabListener(this));
}
but when I swipe between tabs it never call the oncreateview of THIRD fragment but it actually call the oncreateview of THIRD fragment when I swipe to the SECOND fragment (From first to Second) and the oncreate view of second fragment get call along with the first fragment.
I don't understand what's wrong with the flow.
There is nothing wrong with this. when you swipe to new page in viewpager, it automatically loads the two neighbor fragments of current visible fragment. why? because of having better UX.
Can I prevent it from doing that?
No.
Can I extend it to load more neighbor fragments?
yes, setOffscreenPageLimit
Related
public class HomeActivity extends AppCompatActivity {
Context context = HomeActivity.this;
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSectionsPagerAdapter = new
SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
mViewPager.addOnPageChangeListener(new
TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new
TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0 : return new HomeFrag1();
case 1 : return new HomeFrag2();
case 2 : return new HomeFrag3();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
}
When i am switching from fragment 1 to fragment 2 the onStop method of fragment 1 is not called but it gets called when i switch from fragment 2 to fragment 3. When i switch from fragment 2 to fragment 1 the onStart is not called either.
There's a property on ViewPager called offscreenPageLimit - that is set by default to 1, meaning that ViewPager will persist 1 page from either side of the current page - that's why the aforementioned lifecycle callbacks are not being invoked. If you really want to keep only one fragment in-memory you can setOffscreenPageLimit to 0, and that way you will get the behavior you're looking for.
According to this article:
When the page is no longer visible or adjacent to the visible page the ViewPager asks the adapter to destroy it.
The above seems to explain your problem. Switching from 1->2 won't try to destroy Page 1 since it's adjacent to Page 2 which is visible. But switching 2->3 will destroy Page 1 as it's no longer adjacent to the now visible Page 3.
Similarly, switching 2->1 won't re-create Page 1 as it hasn't been destroyed previously.
I suggest you try overriding onPause() and onResume() and see if that works as you'd like.
So I have a Viewpager class which is adding 3 fragments that each have their own layouts. Lets call them Layout/Fragment A, Layout/Fragment B, and Layout/Fragment C.
ViewPager Class:
public class viewpagerMainPagesActivity extends FragmentActivity {
DescriptionPageAdapter pageAdapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_descriptionpages);
List<Fragment> fragments = getFragments();
pageAdapter = new DescriptionPageAdapter(getSupportFragmentManager(), fragments);
ViewPager pager = (ViewPager)findViewById(R.id.viewpager_descriptionpages);
pager.setAdapter(pageAdapter);
}
private List<Fragment> getFragments() {
List<Fragment> fList = new ArrayList<Fragment>();
fList.add(fragmentA.newInstance());
fList.add(fragmentB.newInstance());
fList.add(fragmentC.newInstance());
return fList;
}
}
Now when I call this ViewPager class, it is showing them in the order they are added, that is, it opens onto Fragment A. It is FragmentA as the first screen, FragmentB when you swipe towards the right (2nd screen), and then FragmentC as the last screen on the right.
A - B - C
But I want to have the ViewPager keep this order of the fragments, but open onto FragmentB, so the user can Swipe Right to Fragment A, or swipe left to fragment C.
Can anyone point me in the right direction to do this?
You can center the view by calling:
pager.setCurrentItem(1)//second index for zero based index
just after the following line:
pager.setAdapter(pageAdapter);
When the Activity is instantiated for my Android App, a ViewPager and a FragmentPagerAdpter are also created.
Initially Fragment1 for Tab1 is created. When onCreateView() is called for Fragment1, the ActionBar is also inflated and set to the current activity. So far so good. The display on Android device looks good.
When user press "Add" button on the ActionBar, Fragment2 for Tab2 is created as just described above. And I'm able to swipe back and forth between two tabs. And the ActionBar shows up fine on either Tab1/2.
When a new Fragment is added, it is added to ArrayList, and FragmentPagerAdapter.notifyDataSetChanged() is called. This allows the new Tab to be visible.
However after adding Fragment3 for Tab3, and when I swipe to it, the ActionBar does not show. But Fragment3 for Tab3 is clearly visible. When I swipe back to Fragment2, the ActionBar shows up. When I swipe back to Fragment3, the ActionBar again disappears.
When I add Fragment4 for Tab4, and when I swipe to it, again the ActionBar disappears. However now the ActionBar shows up for Fragment3 for Tab3 which was not the case when it was the last Fragment.
So when there are 3 or more Fragments which were added dynamically, the ActionBar does not show up for the last Fragment. Also the ActonBar does not show up for the first Fragent either for this scenario.
After tracing the calls, onPause() method is called for the first or last Fragment when I swipe to it and the ActionBar is not displayed. For the middle Fragments whose ActionBar shows up fine, onCreateView() method is called when I swipe to one of them.
I'm quite puzzled by the above inconsistent behavior relative to ActionBar display for Fragments. I'm not sure why onPause() is called for the first/last Fragment which is current on display. This seems to be culprit for not having the ActionBar being displayed.
Below are some code snippets:
public class MyApp extends Activity {
protected void onCreate(Bundle icicle) {
....
ViewPager viewPager;
TabsPagerAdapter mAdapter;
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
....
}
public class TabsPagerAdapter extends FragmentPagerAdapter
implements ViewPager.OnPageChangeListener {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
....
public class MyFragment extends Fragment implements {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
.....
View actionBarButtons =
inflater.inflate(R.layout.actionbar,
new LinearLayout(mActivity), false);
... add buttons here....
mActivity.getActionBar().setCustomView(actionBarButtons);
.....
}
I have a FragmentActivity and some fragment in my app.
i need to have Swip ActionBar-Tabs Just inside one fragment , but when i use ActionBar and ViewPager in my project to make Swip ActionBar Tab , make ActionBar in all of fragment No just in one,
hove i can make ActionBar just inside one fragment that not shown in other fragment?
actionabar = getActionBar();
actionabar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
viewpager = (ViewPager) findViewById(R.id.pager);
FragmentManager fm = getSupportFragmentManager();
/** Defining a listener for pageChange */
ViewPager.SimpleOnPageChangeListener pageChangeListener = new ViewPager.SimpleOnPageChangeListener(){
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
actionabar.setSelectedNavigationItem(position);
}
};
/** Setting the pageChange listner to the viewPager */
viewpager.setOnPageChangeListener(pageChangeListener);
/** Creating an instance of FragmentPagerAdapter */
MyFragmentPagerAdapter fragmentPagerAdapter = new MyFragmentPagerAdapter(fm);
viewpager.setAdapter(fragmentPagerAdapter);
actionabar.setDisplayShowTitleEnabled(true);
Tab tab = actionabar.newTab().setText("My Friends").setTabListener(tabListener);
actionabar.addTab(tab);
tab = actionabar.newTab().setText("Android Version").setTabListener(tabListener);
actionabar.addTab(tab);
tab = actionabar.newTab().setText("Android Phones").setTabListener(tabListener);
actionabar.addTab(tab);
Use TabHost (http://developer.android.com/reference/android/support/v4/app/FragmentTabHost.html) instead of ActionBar navigation mode.
I've got a ViewPager with 4 tabs.
I'm using a custom adapter that extends FragmentPagerAdapter.
The problem is that when I change the tab, the first Fragment gets created again although it's not the currently visible.
Moreover, this only happens after changing the tab for the fourth time. E.g. tab1 -> tab2 -> tab3=> onStop from tab1 is called. -> tab2 => onCreateView from tab1 is called (onAttach is not called).
I want to avoid this. I need all tabs to remain always in their state even when they are not currently displayed.
How can I do this?
It's been as easy as using method setOffscreenPageLimit() from ViewPager.
More info: http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)
Viewpager has one public method named setOffScreenPageLimit which indicates the number of pages that will be retained to either side of the current page in the view hierarchy in an idle state.
Activity:
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = findViewById(R.id.container);
mViewPager.setOffscreenPageLimit(3); // change your number here
mViewPager.setAdapter(mSectionsPagerAdapter);
When you instantiate the fragment, call setRetainInstance(true). This will retain the instance state of the fragment. onCreateView will still be called and you will need to make sure that you re use the saved state and just render the views without loading any data again, e.g. by using a boolean to represent if your fragment has already been initialized.
You would do something like this:
public static class MyAdapter extends FragmentPagerAdapter {
#Override
public Fragment getItem(int position) {
MyFragment myFragment = new MyFragment();
myFragment.setRetainInstance(true);
return myFragment;
}
}
class MyFragment extends Fragment {
.
.
.
boolean initialized = false;
ArrayList<MyData> myData = null;
void onCreate(...) {
if (initialized) {
renderViews();
} else {
initialized = true;
loadData();
renderViews();
}
}
}
You don't need to implement onSaveInstanceState(). It will be handled automatically.