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);
Related
The problem is the following, I have a navigation drawer with three fragments A, B and C. Within fragment B I have a ViewPager which in turn has 3 fragments but let's call it B-1, B-2 and B-3. I was reading a lot and trying but I can not do that when I navigate between the navigationDrawer I save the status of all the fragments are A, B, C and all of the ViewPager.
I tried with the freezeText attribute in the xml, keeping everything in a list within my viewpager (this for the 3 fragments of the viewpager, obviously) and I also tried with the savedinstancestate method but I can not get what I want, below I leave my code of the viewpager your adapter I have it in a separate class but it has no code that is not normal manual, if at least we can make it work that would be a breakthrough that I just could not achieve. Thank you
fragment that contains my viewPager:
public class CargarStocksFragment extends Fragment {
..
..
private List<Fragment> fragmentList;
..
..
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("Lista", (Serializable) fragmentList);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState!=null)
fragmentList= (List<Fragment>) savedInstanceState.getSerializable("Lista");
else
fragmentList = new ArrayList<Fragment>();
}
..
..
#Override
public Fragment getItem(int position) {
return new ArticuloFragment();
}
There is 3 TabLayout with ViewPager in my application.
If I swipe for change Tabs then it behaves strangely.
Below is the scenario.
Let's say 3 Tabs A, B, C.
Default Tab A will open when I start App.
Go to B From A - Works OK.
Go to A From B - Works Ok.
Go To B From A - Works Ok.
Go To C From B - Works Ok.
Now Problem Starts here.
Go To B From C - It will Load A and B Both but display Only B.
Why A and B loads if I come from C ??
Below is my code.
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
ViewPagerAdapter adapter;
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
private void setupViewPager(ViewPager viewPager) {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new FragmentOpen(), "OPEN");
adapter.addFragment(new FragmentClose(), "CLOSE");
adapter.addFragment(new FragmentTest(), "TEST");
viewPager.setAdapter(adapter);
}
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);
}
}
I want to load Tabs every time.
For that, I use below code.
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if(adapter != null){
adapter.getItem(position).onResume();
}
Toast.makeText(getApplicationContext(), "Page Selected", Toast.LENGTH_LONG).show();
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
But it will always load both tabs when I came from C.
What I want is: only Tab B must load when came from C, not Both.
Its not possible when using ViewPager. ViewPager loads at least one right/left adjacent fragment of current fragment as per your swipe direction.
If you read the ViewPager documentation, there is a method ViewPager.setOffscreenPageLimit(LIMIT) which supports off screen page limit and its default value is 1.
SetOffscreenPageLimit:
Set the number of pages that should be retained to either side of the
current page in the view hierarchy in an idle state. Pages beyond this
limit will be recreated from the adapter when needed.
This is offered as an optimization. If you know in advance the number
of pages you will need to support or have lazy-loading mechanisms in
place on your pages, tweaking this setting can have benefits in
perceived smoothness of paging animations and interaction. If you have
a small number of pages (3-4) that you can keep active all at once,
less time will be spent in layout for newly created view subtrees as
the user pages back and forth.
You should keep this limit low, especially if your pages have complex
layouts. This setting defaults to 1.
See documentation.
Here are some related answers:
1. ViewPager.setOffscreenPageLimit(0) doesn't work as expected
2. How can make my ViewPager load only one page at a time ie setOffscreenPageLimit(0);
3. How does setOffscreenPageLimit() improve ViewPager performance by retaining more offscreen Fragments?
its Default behavior of ViewPager if you are in A then it loads B
also and when your reach B it will Load C and A also is Loaded now
when to reach at C its destroy the View of A and now when you come
again to B it will Load A again, in a simple way ViewPager Maintain
the One Next and One previous state of View by Default.
to Overcome this you should use ViewPager.setOffscreenPageLimit(number) here number is the count of page to load Simulationally for Next and Previous View.
I had only 3 tabs and settingViewPager.setOffscreenPageLimit(2) worked for me.
Try ViewPager.setOffscreenPageLimit(totTabs - 1)
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 got a xml layout for main activity with some buttons on top of the screens. Below them is placed ViewPager:
<ViewPager android:id="#+id/viewpager">
I also got two fragments in mainactivity.class, each with it's own layout:
frag1 = new Fragment1(); frag2 = new Fragment2(); and viewpager = (ViewPager) findViewById(R.id.viewpager);
Now whats the simplest way to add these two fragments to ViewPager (but without using ActionBar TABS)? I also need to run some code according to which fragment is selected by user, for example make Toast with text "Fragment 2 is selected" when swiped to frag2.
Ok, now I have extended FragmentPagerAdapter: Public class frAdapter extend FragmentPagerAdapter {
public Fragment getItem(int i) { ... }
What I'm supposed to do in getItem() method to add these fragments to viewpager?
My app is a news app, with news listing fragment, NewsDetailsFragment (which contains menu, search, etc). I am using the single activity model and each screen is represented by a Fragment. NewsDetailsFragment includes a ViewPager (gallery).
When I navigate to NewsDetailsFragment initially, the gallery is loaded, now if I load a new instance of NewsDetailsFragment fragment, to choose another news from the menu, doing a search, etc. The ViewPager in the 2nd NewsDetailsFragment won't display the images, although the Log shows that everything works fine, data is there, adapter calls getView()...
So basically if there is 1 loaded gallery ViewPager, any more NewsDetailsFragment won't show their galleries, only if I press Back till I have no fragment (hence no ViewPager running), only then if I open a new instance of NewsDetailsFragment it will load the gallery.
I hope I explained clearly. I tried my best and I'm clueless now.
This is how I pass the gallery data to the ViewPager after it is loaded (code excerpt from NewsDetailsFragment):
ViewPager pager = (ViewPager) getView().findViewById(R.id.vpAlbum);
ArticleAlbumAdapter adapter = new ArticleAlbumAdapter(getActivity().getSupportFragmentManager(), article.album);
pager.setAdapter(adapter);
ArticleAlbumAdapter:
public class ArticleAlbumAdapter extends FragmentStatePagerAdapter
{
private List<String> urlList;
public ArticleAlbumAdapter(FragmentManager fm, List<String> urlList)
{
super(fm);
this.urlList = urlList;
Log.d("ArticleAlbumAdapter()", "urlList=" + urlList);
}
#Override
public Fragment getItem(int position)
{
Log.d("ArticleAlbumAdapter.getItem()", "position=" + position + ", url=" + urlList.get(position));
Fragment image = new AlbumImageFragment();
Bundle bundle = new Bundle();
bundle.putString("url", urlList.get(position));
bundle.putInt("pos", position);
image.setArguments(bundle);
return image;
}
#Override
public int getCount()
{
return urlList.size();
}
}
Pass the ViewPager your current Fragment's getChildFragmentManager() rather than the FragmentManager of the activity. Based on your description, I'm assuming your main screen which creates the first ViewPager is also a Fragment. Since the ViewPager is a child to your Fragment and it in turn is creating child Fragments, it needs the child FragmentManager rather than the main one.