My Activity has a viewpager along with a tablayout. There are three tabs. Now while swiping between the tabs, there is noticeable delay (around 300ms) while i try to very quickly swipe from, say, the first to third tab.
Now the viewpager contains three fragments. I am using a FragmentPagerAdapter to declare the viewpager tabs (as this gave a slight improvement compared to when i used FragmentStatePagerAdapter). Also I have set offScreenPageLimit for the viewpager to 2 (since there are 3 tabs).
Now to find out what was going wrong, I initialised empty fragments for the tabs and the swiping was fine and smooth as expected.
Next, I implemented the full functional code for the middle/2nd tab and left the other two as empty fragment.
Now this is where things get interesting, I was expecting a small delay while i swipe into the middle fragment(it contains nothing but a listview), when it creates it views and plugs the adapter into the listview with data. However, that was not the case. There was a noticeable delay while swiping out of the middle fragment!
Thus I have reason to believe, that while swiping out, where the fragment's view is being removed from screen, there is something I need to take care of which will make the transition smoother.
Related
What I would like to achieve: Have a ViewPager with TabLayout where each Tab contains a new Fragment that has a RecyclerView layout out horizontally and managed by a FragmentPagerAdapter.
What I am struggling with: The default behaviour is that when you get end of the list on one of the tabs, it switches Tabs and snaps (snapping means if you pull over 50% of the viewport, it jumps to either direction). I want it to free-flow and not to snap. Sort of like how it happens in iOS by default.
I got inspired for this setup by the following two CodePath guide:
https://guides.codepath.com/android/google-play-style-tabs-using-tablayout
https://guides.codepath.com/android/ViewPager-with-FragmentPagerAdapter
How should I approach this problem (preferably without any other libraries)?
What I would do is use HorizontalScrollView instead of a ViewPager. The only caveat is that the view pager sends the lifecycle events to fragments as you scroll between them, whereas for HorizontalScrollView you will have to add them initially, and then they will be continuously active unless you manually change that. Also you may have an option to not use the fragments and use simple views depending on what you use the fragments for.
I would definitely not override the touch events for the ViewPager because it does some cleanup when it detects the UP motion, so just swallowing it is not a correct thing to do.
Am running in some weird problem. I have implemented ViewPagerTabStrip by following the tutorial Here
It's working fine and i have implemented Three Tabs.
On the first Page /tab , i am loading the data from server & displaying it in the ListView
The problem is, when i swipe to the Third Page & then i swipe back to Second page, the data of the first page is being loaded from the server again.( View of first tab is re-created.)
From the logs, it seems that this is the behavior of ViewPager & Adapter.
When we are on the first tab, it creates the view of second tab/ page as well in background & when we are on the Second tab, it was doing same for Third tab in background & upon reaching to third tab, it didn't created the view for it self(i.e third tab).
But when we swipe back to second tab, it re created the view of first tab as well.
How to solve this ? we can't afford to load the data from server again and again while swiping through the tabs.
I mean is there any way to stop the reload of data (or re-creation of view) while just swiping through tab pages? It should load the data when the whole fragment activity of View Pager is created and not at the time of swiping.
Any help on this please ?
Yeah, the ViewPager only keeps a certain number of fragments in memory before destroying them- this default number is usually two. Thus, what you have to do is tell the ViewPager to retain those fragments.
The simplest solution is to simply tell the ViewPager to keep three fragments in memory as follows:
viewPager.setOffscreenPageLimit(3);
Here are a few suggested answers on how to retain fragments (with more than just this method) and the reasoning behind the default behaviour as well as these solutions:
ViewPager and fragments — what's the right way to store fragment's state?
retain state of viewpager fragments android
I am trying to implement swipe views with 2 tabs. For that, I am using view pager with 2 fragments. Now, the problem is that as soon as the main activity is opened (that contains those two tabs), onCreateView function is called for both the fragments. Please help me as how can I avoid calling of onCreateView of second fragment when one is in use.
Thanks,
Arpit
ViewPager retains the fragment to the left and to the right of the current view by default. This is to reduce a choppy user experience - that way you can begin swiping left or right and immediately see what is there without delay.
It is possible to disable (or increase the number of fragments to be retained) with setOffscreenPageLimit(0), but seriously consider if this is the right approach.
I have an activity. Inside that activity I have implemented VerticalViewPager in which 3 pages are fed i.e. Upper Page, Middle page and Lower Page. Inside the middle page fragment and Lower page fragment I have separately another ViewPagers(Horizontal).Inside these ViewPagers I have 3/3 pages each. So far I have been able to make them working just fine i.e. on vertical swipe gesture the VerticalViewPager gets triggered and on horizontal swipe gesture native android ViewPager gets triggered. Now I need to sync the horizontal swipe transition between the middle fragment pages and lower fragment pages.
Let me give an example: say I have A,B and C pages inside middle fragment of VerticalViewPager and D,E,F inside the lower vertical fragment. Assume I am in the middle fragment now. So when I swipe from A to B left to right, the lower fragment should also swipe from D to E automatically.
[P.S.: For the horizontal(native) ViewPager to work inside
VerticalViewPager, the horizontal ViewPager Adapter needs to run
in the AsyncTask or threads. So please consider this scenario as
well]
You can make the adapter scope available globally and set the current view or fragment according to the change in the middle fragment.
According to the example:
I have created an android app that uses a ViewPager to swipe through three fragments (each of the three fragments contains a gridview).
I began learning about fragments recently and assumed that after my gridviews were created in their fragments, that each fragment would be in memory and never have to load again.
Recently I noticed that when I swiped from my left fragment, to the middle fragment, then to the right fragment, that the left-most fragment would have to have its gridview filled again with my adapter.
I was just wondering why this happens when I navigate from the left-most fragment to the right-most fragment, but not when I navigate between side-by-side fragments. Does it only keep the most recent fragment in memory and kill the other fragment? Or is there some other reason why an app wouldn't keep all three fragments in memory? My app gets a little laggy and slow when I quickly navigate between fragments, so it would be nice to only have to draw each gridview one time if possible.
I fill my arraylist (used to fill adapter) in onCreate(), and then fill my gridview with the adapter in onActivityCreated(Bundle savedInstanceState)
The ViewPager keeps a certain amount of off-screen tabs (Fragments, of course) in memory. The default, I believe for all devices, is 1. Thus, when you scroll to the far right, only the one to its left will be kept in memory.
If you want your ViewPager to retain all tabs in memory (careful--this can be hard on the device or other running apps), you can set how many off-screen tabs to keep in memory. To do this, use the setOffscreenPageLimit method of ViewPager on your ViewPager object.
Example:
ViewPager pager = (ViewPager) findViewById(R.id.pager); // Your pager's ID
pager.setOffscreenPageLimit(2); // Will retain 2 off-screen tabs + your selected tab
Hope this helps!
It's the nature of how a FragmentPagerAdapter and FragmentPagerStateAdapter work. From Google's site:
The fragment of each page the user visits will be kept in memory, though its view hierarchy may be destroyed when not visible.
Meaning, your GridView is refilling because your ViewPager killed the view and has to rebuild it.
EDIT: If you need to keep all three fragment Views in memory to speed things up, then you would have to create your own PagerAdapter that stores the views in instantiateItem(ViewGroup, int) inside an Collection of some sort.
Alternatively, if you are using Google's example verbatim, then you probably are doing something like this:
#Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
In which case, you're rebuilding a new fragment each time the ViewPager requests one.
By default ViewPager keeps in an idle state one fragment from the left and one from the right of the current page. You can change this behaviour with ViewPager.setOffscreenPageLimit(). See docs