Background:
I am using a variant of ViewPager which instead of scrolling in horizontal direction, it scrolss in vertical direction.
VerticalViewPager
:
https://android.googlesource.com/platform/packages/apps/DeskClock/+/master/src/com/android/deskclock/VerticalViewPager.java
android.support.v4.app.FragmentStatePagerAdapter
is being used to set the contents in VerticalViewPager
.
I am creating and returning a new instance of android.support.v4.app.Fragment
from FragmentStatePagerAdapter
every time getItem()
of FragmentStatePagerAdapter
is called as listed below:
@Override
public Fragment getItem(int position) {
return PreviewFragment.getNewFragmentInstance(position);
}
PreviewFragment
renders the content that may not fit on the screen.
In order to show all the contents that doesn't fit on to the screen, android.support.v4.widget.NestedScrollView
is used as a parent element of PreviewFragment
layout.
Problem:
Content of PreviewFragment
does scroll for position 0 as expected.
But swiping to page for position 1 is very difficult in terms that one has to perform fling or swipe operation many times in order to switch to next page.
Also, fling or swipe back to position 0 is very very difficult or almost impossible.
Required:
Fling or swipe or switch to next instance of PreviewFragment
should be smooth.
In other words scrolling of content should be smooth while keeping in mind that the swipe to next page should also work smoothly.
Link to the sample project as mentioned above
i go through your Github code. I made it work for you. I have sent a pull request too. Problem was that onInterceptTouchEvent
if returned true
it makes ViewPager
to scroll and if we return it false
it disable ViewPager
touch and make NestedScrollView
to scroll. So here i did was to check if NestedScrollView
needs to be scrolled then i returned it false
if NestedScrollView
is on top or bottom, I returned it to true
. I am posting code here. You can modify it and make it more clean.
Github Link - https://github.com/karanatwal/vertical-viewpager-nestedscrollview
Below is VerticalViewPager
code -
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean toIntercept = super.onInterceptTouchEvent(flipXY(ev));
// Return MotionEvent to normal
float x = ev.getX();
flipXY(ev);
int direction=1;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartDragX = x;
break;
case MotionEvent.ACTION_MOVE:
if (mStartDragX < x ) {
direction=-1;
} else if (mStartDragX > x) {
direction=1;
}
MainActivity.MyPagerAdapter adapter = (MainActivity.MyPagerAdapter)this.getAdapter();
if (adapter.getCurrentFragment() instanceof FragmentViewPager){
FragmentViewPager fragmentViewPager = (FragmentViewPager)adapter.getCurrentFragment();
toIntercept = !fragmentViewPager.getNestedScrollView().canScrollVertically(direction);
int range = fragmentViewPager.getNestedScrollView().computeVerticalScrollRange();
int offset = fragmentViewPager.getNestedScrollView().computeVerticalScrollOffset();
int extent = fragmentViewPager.getNestedScrollView().computeVerticalScrollExtent();
int percentage = (int)(100.0 * offset / (float)(range - extent));
System.out.println(" range: "+range);
System.out.print(" offset: "+offset);
System.out.print(" extent: "+extent);
System.out.print(" percentage: "+percentage);
System.out.print(" direction: "+direction);
if (fragmentViewPager.getNestedScrollView().computeVerticalScrollOffset()==0 && direction==-1){
//top
return true;
}
else if (percentage>99 && direction==1){
//bottom
return true;
}else {
//scroll nestedscrollview
return false;
}
}
break;
}
return toIntercept;
}
Your MyPagerAdapter
-
public class MyPagerAdapter extends FragmentStatePagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
private Fragment mCurrentFragment;
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
//...
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (getCurrentFragment() != object) {
mCurrentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
@Override
public android.support.v4.app.Fragment getItem(int pos) {
switch (pos) {
case 0:
return FragmentViewPager.newInstance("Title Start", R.drawable.ic_launcher_background);
case 1:
return FragmentViewPager.newInstance("Rock", R.drawable.rock);
case 2:
return FragmentViewPager.newInstance("Paper", R.drawable.paper);
case 3:
return FragmentViewPager.newInstance("Scissors", R.drawable.scissors);
case 4:
return FragmentViewPager.newInstance("Title End", R.drawable.ic_launcher_background);
default:
return FragmentViewPager.newInstance("Default Title", R.drawable.rock);
}
}
@Override
public int getCount() {
return 5;
}
}
For avoiding Restricted API methods- Use below logic as a alternate
//offset , range and extent
int scrollY = scrollView.getScrollY();
int scrollContentHeight = scrollView.getChildAt(0).getHeight();
int screenHeight = Utility.getScreenHeight(context);
int statusBarHeight = Utility.getStatusBarHeight(context);
double percent = ((((float) scrollY) / ((float) (scrollContentHeight - screenHeight + statusBarHeight))));
All you need is percentage of scroll and direction of swipe. There are alot more questions on SO for finding scroll percentage and swipe direction like this and this. You should do little R&D for it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With