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.
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 .
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.
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.
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.
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.
You can disable paging in your viewpager by simply calling this method on your viewpager
view_pager.setUserInputEnabled(false)
Read more
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