I want to swipe between fragments, and I am currently using the viewpager.
There is one problem though: When I swipe to the right, entries made in EditTexts of the current
fragment need to be validated, and only if the input is ok, it should be swiped to the next page.
I managed to do that by disabling the viewpager when necessary, however then I also cannot swipe to the left (i.e. the previous fragment), since the method to validate the input (onPageScrolled(...)) is not called anymore due to the fact that the viewpager is disabled. It is only enabled again when I type something in the EditText.
I haven't found a way to deal with that problem yet.
So I'd like to know if there is an alternative to using fragments with swipe gestures? Maybe in combination with the viewpager's setCurrentItem() method, but without using the viewpagers scrolling-animation?
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.
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 scrollable tabs + swipe activity with 3 different fragments on it. It works well but I don't want my fragments to be destroyed when I navigate between them. For example, when I create the activity, it's shown the first fragment but it's created the second one too. When I swipe to the second fragment, the third is created, so I can swipe to the third one and it will be created before I open it. When I return to the second one, my third fragment still stays created but when I return to the first one, the third fragment is deleted.
There would be any way to avoid this? I don't want my fragments to be deleted when I navigate between them.
If you use a ViewPager, it has a method called setOffscreenPageLimit(int limit). Try and see if setting that higher works
This answer should help you figure out what's going on. Pretty much you are most likely using a FragmentStatePagerAdapter, when you should be using a FragmentPagerAdapter. That keeps it from deleting fragments not in view.
If, for performance reasons, you need to have the fragments deleted when they aren't being used, there are other options. Either look at why the performance is that bad when you have only 3 tabs (It shouldn't be unless you are doing something wrong with a listview, or have a map open, etc.) or you can code the fragments to save their state when they are being destroyed (which should be happening anyways with a FragmentStatePagerAdapter).
If that doesn't help, we'll need more info on what you are doing exactly to help.
The ViewPager object is implemented such that the next screen is already created in memory before the user swipes to it. ViewPager has a method setOffscreenPageLimit(n) in which you can set the number of ViewPager fragments that are created in advance, but n=0 is not allowed. The reason behind that is to garantee a 'smooth user experience'. In my case however then content of page n+1 is determined by what the user has done on page n. For instance if the user has clicked on a checkbox on page n, it can happen that some widget should not be shown on page n+1. My question is: how can I ensure that page n+1 is recreated? If that goes at the cost of a 'smooth user experience' so be it. I am able to intercept the swipe event in:
pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener()
In that method I can call a refresh() method of the current fragment. The problem is: what do I do in that refresh() method or is this the wrong approach? The user interface I want to recreate is in the onCreate method, a callback method. Or can't this work and do I need to replace the Fragment (n+1) in memory with a new one and if so, how do I do that?
Any help would be appreciated.
Trying to replace the fragment associated with a page in a ViewPager is going to be the responsibility of your fragment-based PagerAdapter. I am not aware of an easy way to accomplish that with FragmentPagerAdapter or FragmentStatePagerAdapter. My ArrayPagerAdapter can handle it better, though I don't offer a direct replace() operation.
In your case, the better solution is to adjust the fragment that you have, rather than to replace the fragment outright. In theory, this should be possible for just about any degree of change. In practice, there is probably a level of complexity after which trying to replace the fragment would be simpler than trying to have a mashup of all possible fragments.
Note that nested fragments might be another option, where the N+1th page was a placeholder and ran a FragmentTransaction to populate itself when shown. Nested fragments are tricky and quirky.
With regards to the "holes", View.INVISIBLE indicates that you want the widget to continue taking up space (e.g., so stuff after it in a LinearLayout does not move), but do not draw the pixels. View.GONE means that the View is totally ignored for layout purposes, though it is still in the hierarchy and so can be easily toggled back to View.VISIBLE if needed. Another possibility would be to remove the View entirely from the parent container, though this should have no visible change when compared with View.GONE.
I use ActionBarSherlock compatibility library and experience a strange behavior when paging between tabs of Action Bar. Each tab contains a simple Fragment, nothing special. I observed that fragment's onCreateView method is called too often even though there is no screen orientation change. It looks like some kind of pre-caching. I have three tabs there, when the activity is created, the onCreateView is called only for the first two fragments. The last fragment doesn't create view until I page one step forward. The same behavior occurs when paging from the last tab to the first.
Has anybody any idea why this occurs? I would assume creating all views at once, when the parent activity finishes its creating. I don't want to create views again and again, there are no changes in the fragments, they are static. It has no sense and causes paging to be sluggish a bit...
After a few hours I found what's happening there. ViewPager has a default setting DEFAULT_OFFSCREEN_PAGES which sets the maximum number of views (fragments in my case) to be stored in the view container of ViewPager. It is obviously some kind of resource optimization; invisible views can be thrown away and restored when needed.
There is nothing easier then change this value by setOffscreenPageLimit(int limit) setter which I overlooked.
I think it was done consciously to increase user experience.
The same way ViewPager from compatibility lib is implemented.
Anyway, sources are available.