Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I decided to give a try on the new and now available stable release of ViewPager2.
My ViewPager2 have a lot of pages, and I am using TabLayout to give each page (fragment) scrollable tab titles, but I am facing a delay when loading the ViewPager2 for the first time in my view.
Is this the normal behavior?
I figured it out what was causing the ViewPager2 initial delay to load the pages.
It happens I was using TabLayout from com.google.android.material.tabs.TabLayout along with the ViewPager2 to give scrollable tab titles to each page. But if you have a lot of pages which is my case, the UI takes time to setup each tab and place in the UI.
The solution is to remove the TabLayout from ViewPager2, and if you need to display a title, use the ToolBar as title page indicator for each page by changing and setting ToolBar text according to your needs.
Looking the bright side you end up with more clean UI, by having more space in screen for your ViewPager2 to display its content to the user.
Another thing I noticed is if you want to take full advantage of ViewPager2 performance benefits, then use the default viewpager's offscreenPageLimit, as stated bellow:
public void setOffscreenPageLimit (int limit)
Set the number of pages that should be retained to either side of the currently visible page(s). Pages beyond this limit will be recreated from the adapter when needed. Set this to OFFSCREEN_PAGE_LIMIT_DEFAULT to use RecyclerView's caching strategy. The given value must either be larger than 0, or #OFFSCREEN_PAGE_LIMIT_DEFAULT.
Pages within limit pages away from the current page are created and added to the view hierarchy, even though they are not visible on the screen. Pages outside this limit will be removed from the view hierarchy, but the ViewHolders will be recycled as usual by RecyclerView.
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. By default it is set to OFFSCREEN_PAGE_LIMIT_DEFAULT.
https://developer.android.com/reference/androidx/viewpager2/widget/ViewPager2.html#setOffscreenPageLimit(int)
That being said I strongly recommend the replacement of your ViewPager to ViewPager2 for all cases, because ViewPager is no longer receiving Google support, and ViewPager2 has a lot to offer other than what I spoke here:
RTL (right-to-left) layout support
Vertical orientation support
Reliable Fragment support (including handling changes to the underlying Fragment collection)
Dataset change animations (including DiffUtil support)
https://developer.android.com/jetpack/androidx/releases/viewpager2
There's a whole set of improvements over ViewPager:
RTL (right-to-left) layout support
Vertical orientation support
Reliable Fragment support (including handling changes to the underlying Fragment collection)
Dataset change animations (including DiffUtil support)
These features will never be fixed in ViewPager, so migrating to ViewPager2 would be the only way to get these features.
Related
I'm writing an app with multiple tabs. Every tab is a fragment and every tab uses the same layout file. You can change to the next tab by swiping (handled by a SwipeAdapter). Inflating the same layout for every tab again is quite inefficient and makes the app lag. Is there a way to inflate the layout once in the beginning and to reuse the inflated layout for all tabs?
Or alternatively, is there a way to do so with e.g. three inflated layouts? (-> one for each the currently displayed tab and both neighbours, so when you swipe from tab 4 to 5, the inflated layout of tab 3 - which is not needed anymore - is used for tab 6)
I know you can reuse inflated views with a listview, but it wouldn't work here because I want the user to swipe instead of continuous scrolling.
Welcome to StackOverflow. Use RecyclerView with a SnapHelper (works both horizontally and vertically). If you Google it you will find many tutorials.
Alternatively you can use ViewPager2, which is in alpha state (if you can wait for it to be stable). It is based in RecyclerView, and is an update to the old ViewPager to bring it to 2019. See this tutorial for example Hands on With ViewPager2. See also ViewPager2 releases page at Google to keep track of development progress.
I am a little bit confused on how should I approach this particular case of doing some swipes between fragments.
So yea, I asked ViewPager or RecyclerView, because these 2 are my only options, if anyone can come up with a better idea, it is really welcome.
The flow is the following, I have a Main Timeline(ListView), each item of it opens a fragment with details about it. What I would actually want to do is to swipe between these full screen fragments without going back to MTL and open another item of the list.
You would ask me what I tried, well:
RecyclerView - HORIZONTALLY oriented as a root of the fragment, and each item of this RV had the details of each event. The problem with this is that it gets really buggy because I have a huge logic inside each item(like, another RV - horizontally , a PagerView also horizontally to swipe between images (or a youtube frame that is being played if is the case. Plus a lot of other stuff in this, so the logic of parent RV inside the onBindViewHolder() is really tricky.
Would be better to use a PagerView with fragments(since I have the DetailsFragment kind of ready) ? The problem here is that I need a certain number of swipes, right ?
Go with viewpager.
Because creating fragments inside recyclerview causes recyclerview performs to slow down.Also to create fragments in onBindViewHolder() dynamically every time you need different unique id of frame layout to load which will be tough to generate.
For more information on why recycler view is bad idea to load fragments check this.
Fragment replacing in RecyclerView item
Also try to use the ViewPager with an implementation of FragmentStatePagerAdapter. The adapter will optimize the memory usage by destroying fragments that are not visible at a given moment.
Check the documentation for details and code sample.
https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html
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.
Here is a sample from duolingo app:
I want to implement a similar feature. I can use ViewPager to make swiping tabs. What I can't seem to figure out is how to display the adjacent tabs (part of it) alongside the current tab, which is in the center.
I initially thought of implementing this using horizontal LinearLayout, but I don't know how to make the snapping effect. And it also seemed more reasonable to use something which already provides you with swiping and snapping than try to implement your own.
Using ViewPager also let's me use fragments and memory management is also effective for cases of more than a few tabs.
Any help will be appreciated. Thank You in advance.
I am using a view pager to show a list of images, it works fine but the main issue is that when I swipe between images, there is some kind of fading between images.
for example if I have 5 pictures and the first one is visible when i swipe the second one is visible directly.
if i decided to swipe faster, it shows white screen then the image appears "moving from first to third quickly - as example".
I think the fragment is being recycled - is there any way to avoid this ??
It's hard to tell with no details on your implementation, but just to answer your last question (I'm not sure if it will necessarily solve your problem) - if you are using a fragments in your ViewPager and are currently using a FragmentStatePagerAdapter, you can switch to a FragmentPagerAdapter, which will keep the fragments in memory (although it will of course use more memory, so you might not want to do it if you have a large number of fragments in your ViewPager). You can also specify how many offscreen pages for the ViewPager to keep using
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(2);
In the above case it would keep 2 pages on each side of the currently viewed page. Sorry, I would have confirmed the specific problem with you before posting this answer, but I don't have the status yet :(