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.