Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to disable ViewPager paging

I'm developing an app which have a ViewPager as a menu. Each fragment has a bunch of child views which can be ListView, ScrollView, LinearLayout, etc... One of this fragments have a settings button which toggles a settings panel (LinearLayout wrapper) with a ScrollView and some LinearLayout (buttons) and SeekBar as childs. This settings panel is animated with a slide up or down animation (when dismissed) and when it's visible I disable the ViewPager paging:

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (!pagingEnabled && event.getAction() == MotionEvent.ACTION_MOVE) {
        return true;
    }
    return super.onTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (!pagingEnabled && event.getAction() == MotionEvent.ACTION_MOVE) {
        return true;
    }
    return super.onInterceptTouchEvent(event);
}

public boolean isPagingEnabled() {
    return pagingEnabled;
}

public void setPagingEnabled(boolean pagingEnabled) {
    this.pagingEnabled = pagingEnabled;
}

But this came with a problem, every time the panel is up all it child views wouldn't receive the OnTouchEvent and that's why I've added a GestureDetector.SimpleOnGestureListener:

protected class YScrollDetector extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        Log.i(C.TAG, "distanceX " + distanceX + " distanceY " + distanceY);
        return Math.abs(distanceY) < Math.abs(distanceX);
    }
}

and changed my ViewPager onInterceptTouchEvent to:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (!pagingEnabled && event.getAction() == MotionEvent.ACTION_MOVE && (mGestureDetector != null && mGestureDetector.onTouchEvent(event))) {
        return true;
    }
    return super.onInterceptTouchEvent(event);
}

This works, the panel buttons receive their onClick, the ListView swipes, etc... but this doesn't work so perfect because Math.abs(distanceY) < Math.abs(distanceX) it's not that accurate. If I fast swipe up and down or diagonally or if I touch a button with a minor swipe the onInterceptTouchEvent will return true because mGestureDetector.onTouchEvent(event) will return true too.

After some google search I came across this:

viewPager.requestDisallowInterceptTouchEvent(true);

And I tried something like this:

myListView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        viewPager.requestDisallowInterceptTouchEvent(true);
        return false;
    }
});

And it works really well because ViewPager.onInterceptTouchEvent it's called first with MotionEvent.ACTION_DOWN and then myListView.setOnTouchListener it's called right after and disallows the remaining MotionEvent actions (MOVE and UP) and I can fast swipe up, down, sides ways, etc. The ViewPager wont page but the ListView swipes like a charm.

But a problem still remains, I've to add this requestDisallowInterceptTouchEvent(true) to all child views onTouchEvent, and it's not elegant code.

So my question is, I am on the right path? Is there anyway to avoid adding this listener to all the panel child views (of course if I have to I'll do it in the most generic way)?

Thanks for your time.

like image 335
GuilhE Avatar asked Sep 19 '14 14:09

GuilhE


People also ask

How do I stop ViewPager from scrolling?

A simple solution is to create your own subclass of ViewPager that has a private boolean flag, isPagingEnabled . Then override the onTouchEvent and onInterceptTouchEvent methods. If isPagingEnabled equals true invoke the super method, otherwise return .

Is ViewPager deprecated?

This method may be called by the ViewPager to obtain a title string to describe the specified page. This method is deprecated. This method should be called by the application if the data backing this adapter has changed and associated views should update.

How do I turn off swipe in ViewPager Kotlin?

There is no built in way to disable swiping between pages of a ViewPager, what's required is an extension of ViewPager that overrides onTouchEvent and onInterceptTouchEvent to prevent the swiping action. To make it more generalised we can add a method setSwipePagingEnabled to enable/disable swiping between pages.

When should I use ViewPager?

ViewPager in Android is a class that allows the user to flip left and right through pages of data. This class provides the functionality to flip pages in app. It is a widget found in the support library. To use it you'll have to put the element inside your XML layout file that'll contain multiple child views.


2 Answers

Disabling paging should be as simple as returning false from both onInterceptTouchEvent and onTouchEvent. You shouldn't need extra gesture detection to get around the ViewPager. Extend ViewPager like this:

public class MyViewPager extends ViewPager {
    private boolean pagingEnabled = true;

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

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

    public void setPagingEnabled(boolean pagingEnabled) {
        this.pagingEnabled = pagingEnabled;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return pagingEnabled && super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return pagingEnabled && super.onTouchEvent(event);
    }

}

I use the same thing (with a different name) for the same reason in one of my apps and it definitely works.

like image 87
Karakuri Avatar answered Sep 30 '22 19:09

Karakuri


You can disable paging in your viewpager by simply calling this method on your viewpager

view_pager.setUserInputEnabled(false)

Read more

like image 24
Farhazul Mullick Avatar answered Sep 30 '22 20:09

Farhazul Mullick