8

I have a fragmentPagerAdapter viewpager with a few fragment classes inside. So this viewpager scrolls horizontally left and right with swipes. The thing is that on each page my values exceed the page size and I need to scroll vertically to see them all. But I can't enable any vertical scroll. I have removed any scrollviews I had and got my code into a working state. (I want something like the Android app store: scroll horizontally for categories and vertically to see the apps.)

Here is my code:

MyFragmentPagerAdapter:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

        <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:isScrollContainer="true">

            <android.support.v4.view.PagerTitleStrip
                android:id="@+id/pager_title_strip"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="top"
                android:background="#33b5e5"
                android:paddingBottom="4dp"
                android:paddingTop="4dp"
                android:textColor="#fff" />
        </android.support.v4.view.ViewPager>
</RelativeLayout>

The fragment activity that needs the vertical scrolling:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="10dp"
        android:text="Last fill-up spent :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/textView1"
        android:layout_marginTop="15dp"
        android:text="Month total spent :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/currentMoneySpentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView2"
        android:layout_marginLeft="24dp"
        android:layout_toRightOf="@+id/textView1"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/monthTotalSpentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/textView2"
        android:layout_alignLeft="@+id/currentMoneySpentText"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView2"
        android:layout_below="@+id/textView2"
        android:layout_marginTop="15dp"
        android:text="Year total spent :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView3"
        android:layout_below="@+id/textView3"
        android:layout_marginTop="15dp"
        android:text="Since 1st addition :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/yearTotalSpentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView4"
        android:layout_alignLeft="@+id/monthTotalSpentText"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/firstTotalSpentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/textView4"
        android:layout_alignLeft="@+id/yearTotalSpentText"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView6"
        android:layout_below="@+id/textView6"
        android:layout_marginTop="1dp"
        android:text="since last addition :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView8"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView7"
        android:layout_below="@+id/textView7"
        android:layout_marginTop="15dp"
        android:text="Distance covered"
        android:textSize="15dp" />
</RelativeLayout>

Here are the first few lines of my fragment class, which are relevant:

public class MyFragmentDetails extends Fragment {

private RelativeLayout ll;
private FragmentActivity fa;
DBAdapter db;

// MyFragmentFuel fFuels;
private String carSelected, m, y, lowestDistance, highestDistance;

BroadcastReceiver receiver;
int highestDay = 0;
int lowestDay = 31;

public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
}

@SuppressWarnings("static-access")
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    fa = super.getActivity();
    super.onCreate(savedInstanceState);
    ll = (RelativeLayout) inflater.inflate(
            R.layout.activity_add_fuel_details, container, false);
ford
  • 10,687
  • 3
  • 47
  • 54
  • http://stackoverflow.com/questions/8381697/viewpager-inside-a-scrollview-does-not-scroll-correclty have you try this? – dmnlk Mar 22 '13 at 06:56
  • ive seen this code but i dont know where should i use it. – antonis lambrianides Mar 22 '13 at 07:12
  • you use these code on onStart()method in your Fragment class which is inflate MyFragmentPagerAdapter layout. – dmnlk Mar 22 '13 at 07:19
  • I fail to see what your problem is. What is not working? My issue is that if there is content that is to be scrollable vertical, the swipe effect to swithc "page" in the pager is lost, as any movement in vertical direction "releases" the drag effect. So when u try to swipe left/right, you often fail because your finger is not moving EXACTLY horizontal. – Ted Mar 24 '14 at 14:41

4 Answers4

5

The official widget ViewPager2 supports both vertical and horizontal scrolling.

<androidx.viewpager2.widget.ViewPager2 xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:orientation="vertical" />

You can read more here and you can checkout the sample project from github.

makata
  • 2,188
  • 2
  • 28
  • 23
2

Try putting your content in scroll view like this:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
 <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="10dp"
        android:text="Last fill-up spent :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/textView1"
        android:layout_marginTop="15dp"
        android:text="Month total spent :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/currentMoneySpentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView2"
        android:layout_marginLeft="24dp"
        android:layout_toRightOf="@+id/textView1"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/monthTotalSpentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/textView2"
        android:layout_alignLeft="@+id/currentMoneySpentText"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView2"
        android:layout_below="@+id/textView2"
        android:layout_marginTop="15dp"
        android:text="Year total spent :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView3"
        android:layout_below="@+id/textView3"
        android:layout_marginTop="15dp"
        android:text="Since 1st addition :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/yearTotalSpentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView4"
        android:layout_alignLeft="@+id/monthTotalSpentText"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/firstTotalSpentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/textView4"
        android:layout_alignLeft="@+id/yearTotalSpentText"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView6"
        android:layout_below="@+id/textView6"
        android:layout_marginTop="1dp"
        android:text="since last addition :"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/textView8"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView7"
        android:layout_below="@+id/textView7"
        android:layout_marginTop="15dp"
        android:text="Distance covered"
        android:textSize="15dp" />
 </LinearLayout>
</ScrollView> 

After that if you want to do any specific event on your scroll then use :

This is applicable android version marshmallow and above:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                mScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
                    @Override
                    public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                        if (view.getTop() == scrollY) {
                            Log.e(TAG, "onScrollChange: top");
                        } else {
                          
                        }
                    }
                });
            }

 

For lower versions you can use:

final ViewTreeObserver.OnScrollChangedListener onScrollChangedListener = new
                    ViewTreeObserver.OnScrollChangedListener() {

                        @Override
                        public void onScrollChanged() {
                            int scrollY = mScrollView.getScrollY(); // For ScrollView
                            int scrollX = mScrollView.getScrollX(); // For HorizontalScrollView
                            // DO SOMETHING WITH THE SCROLL COORDINATES
                            if (view.getTop() == scrollY) {

                                Log.e(TAG, "ViewTreeObserver onScrollChange: top" );
                            } 
                        }
                    };
            mScrollView.setOnTouchListener(new View.OnTouchListener() {
                private ViewTreeObserver observer;

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (observer == null) {
                        observer = mScrollView.getViewTreeObserver();
                        observer.addOnScrollChangedListener(onScrollChangedListener);
                    }
                    else if (!observer.isAlive()) {
                        observer.removeOnScrollChangedListener(onScrollChangedListener);
                        observer = mScrollView.getViewTreeObserver();
                        observer.addOnScrollChangedListener(onScrollChangedListener);
                    }

                    return false;
                }
            });
Christopher Moore
  • 15,626
  • 10
  • 42
  • 52
Sarthak Sharma
  • 246
  • 2
  • 11
2

Create a class in your project put this

public class VerticalViewPager extends ViewPager {

public VerticalViewPager(Context context) {
    super(context);
    init();
}

public VerticalViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

private void init() {
    // The majority of the magic happens here
    setPageTransformer(true, new VerticalPageTransformer());
    // The easiest way to get rid of the overscroll drawing that happens on the left and right
    setOverScrollMode(OVER_SCROLL_NEVER);
}

/**
 * Swaps the X and Y coordinates of your touch event.
 */
private MotionEvent swapXY(MotionEvent ev) {
    float width = getWidth();
    float height = getHeight();

    float newX = (ev.getY() / height) * width;
    float newY = (ev.getX() / width) * height;

    ev.setLocation(newX, newY);

    return ev;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
    swapXY(ev); // return touch coordinates to original reference frame for any child views
    return intercepted;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapXY(ev));
}

private class VerticalPageTransformer implements ViewPager.PageTransformer {

    @Override
    public void transformPage(View view, float position) {

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        } else if (position <= 1) { // [-1,1]
            view.setAlpha(1);

            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);

            //set Y position to swipe in from top
            float yPosition = position * view.getHeight();
            view.setTranslationY(yPosition);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

}

in XML call this class instead of android.support.v4.view.ViewPager

Aman Jham
  • 478
  • 6
  • 18
Ramkumar.M
  • 681
  • 6
  • 21
0

Try wrapping the contents in a NestedScrollView. If the scrolling still doesn't work (it didn't in my case), try adding an OnTouchListener that calls requestDIsallowInterceptTouchEvent(true) on its parent if you're scrolling vertically:

scrollView.setOnTouchListener(new View.OnTouchListener() {
        int dragthreshold = 30;
        int downX = 0;
        int downY = 0;

        @Override
        public boolean onTouch(View view, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downX = (int) event.getRawX();
                    downY = (int) event.getRawY();
                    break;

                case MotionEvent.ACTION_MOVE:
                    int distanceX = Math.abs((int) event.getRawX() - downX);
                    int distanceY = Math.abs((int) event.getRawY() - downY);

                    if (distanceY > distanceX) {
                        view.getParent().requestDisallowInterceptTouchEvent(true);
                    } else if (distanceX > distanceY && distanceX > dragthreshold) {
                        view.getParent().requestDisallowInterceptTouchEvent(false);
                    }
                    break;

                case MotionEvent.ACTION_UP:
                    view.getParent().requestDisallowInterceptTouchEvent(false);
                    break;
            }
            return false;
        }
    });
Mavamaarten
  • 1,959
  • 18
  • 19