3

I have ViewPager with three fragments and one of them is FrameLayout with ScrollView inside:

<FrameLayout 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">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:id="@+id/table"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"/>
    </ScrollView>

    <Button
        android:id="@+id/buttonRemove"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bg_button_red"
        android:layout_gravity="bottom"
        android:layout_margin="4dp"
        android:text="@string/button_remove_last_round"
        android:textColor="#ffffff"
        android:textSize="24sp"/>


</FrameLayout>

and if I swipe over button, it works. But if I swipe over the ScrollView, it doesn't work, only scroll up/down works

EDIT: I tried to override OnTouchEvent of Scrollview:

@Override
public boolean onTouchEvent(MotionEvent ev) {

    switch (ev.getAction()){
        case MotionEvent.ACTION_DOWN:
            touchX = ev.getX();
            touchY = ev.getY();
            return super.onTouchEvent(ev);//if I change it to 'break', then only swipe works, but no scroll
        case MotionEvent.ACTION_MOVE:
            if(Math.abs(touchX-ev.getX())<40){
                return super.onTouchEvent(ev);//Scroll works perfectly
            }else{
                return false;//Scroll disabled, but swipe still not working
            }
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            touchX=0;
            touchY=0;
            break;
    }
    return false;
}

Now I can disable scroll, but swipe still not working, if the difference between X points more than 40, I pass the event to the viewpager, but the viewpager's onTouchListener doesn't get this event;

Alexander Tumanin
  • 1,638
  • 2
  • 23
  • 37

3 Answers3

5

Ok, I found the solution with help of @yedidyak. I wrote my custom ScrollView:

public class CustomScrollView extends ScrollView {

float touchX = 0;
float touchY = 0;

ViewPager parentPager;

public void setParentPager(ViewPager parentPager) {
    this.parentPager = parentPager;
}

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

public CustomScrollView(Context context) {
    super(context);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {

    switch (ev.getActionMasked()){
        case MotionEvent.ACTION_DOWN:
            touchX = ev.getX();
            touchY = ev.getY();
            return super.onTouchEvent(ev);
        case MotionEvent.ACTION_MOVE:
            if(Math.abs(touchX-ev.getX())<40){
                return super.onTouchEvent(ev);
            }else{
                if (parentPager==null) {
                    return false;
                } else {
                    return parentPager.onTouchEvent(ev);
                }
            }
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            touchX=0;
            touchY=0;
            break;
    }
    return super.onTouchEvent(ev);
}
}

then in the fragment I put the viewpager to this view and it works perfectly

Alexander Tumanin
  • 1,638
  • 2
  • 23
  • 37
  • Perfect! I just have a tiny question. How would changing that 40 affect the scrolling? Bigger = More Area? or the Opposite? – Ayman Salah Sep 23 '16 at 12:15
  • 2
    I would say so: the smaller that number (40) the more precise your vertical movement has to be to scroll the view vertically. E.g. if you set 400, you will never can swipe left-right, only scroll up-down will work. If you set 4 - otherwise, you'll never scroll, only swipe. – Alexander Tumanin Sep 23 '16 at 12:59
  • Thanks a lot, that helped. – Ayman Salah Sep 24 '16 at 12:05
  • Would it be possible to see the full project? I don't see how you set the parentPager in your CustomScrollView from the Fragment class. Thank you – Loebre Dec 06 '16 at 12:02
  • 1
    In your Fragment's `onCreateView()` you can do like `ViewPager parentPager = (ViewPager) rootView.findViewById();` then `CustomScrollView scrollView= (CustomScrollView ) rootView.findViewById();` and then `scrollView.setParentPager()parentPager` – Alexander Tumanin Dec 06 '16 at 12:19
1

The problem is that it isn't clear what scroll you want to happen, that of the ViewPager or that of the scrollview. If you really need a scroll-inside-a-scroll, then you need to override the OnTouchListener of the inner scrollview and add code that decides when to catch and use the touch, and when to pass it back to the parent views.

In this case, you can do something that tests if the swipe is up/down, and then keep the touch, otherwise if the swipe is sideways then passes it back.

yedidyak
  • 1,964
  • 13
  • 26
  • thanks, your idea is clear. But how can I split these two events, up/down and left/right? – Alexander Tumanin Dec 13 '15 at 13:25
  • If the action is down, then store the X and Y values. Then on the next action check what has changed more. If the change in X is more than the change in Y, then it's sideways. There are a lot of code tutorials around for working with touch events to recognise gestures. – yedidyak Dec 13 '15 at 13:27
0

For Future Readers living in +2019

use ViewPager2 to avoid this problem. you can find good example of ViewPager2 implementation at this topic.

Saeed Arianmanesh
  • 1,269
  • 2
  • 22
  • 33