Skip to content

Instantly share code, notes, and snippets.

@colinmadere
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save colinmadere/9b577871d015778b1497 to your computer and use it in GitHub Desktop.
Save colinmadere/9b577871d015778b1497 to your computer and use it in GitHub Desktop.
CooperativeScrollGestureListener
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewGroup;
/**
* Detects if scroll gesture happens, and if the secondary (often, the "inner" scrollable is at the
* edge in the direction the gesture is in, have the primary scrollable process the gesture
*/
public class CooperativeScrollGestureListener implements GestureDetector.OnGestureListener {
private boolean isInGesture = false;
private boolean isScrollingVertical = false;
private ViewGroup mPrimaryView;
private ICoopInnerScrollableView mSecondaryView;
private GestureDetector mGestureDetector;
/**
* You may pass in 'null' for the 'secondaryView' parameter if you do NOT want the outer view
* to scroll when you hit the top/bottom of the inner scroll view. This will still make the
* inner scroll work when inside an outer scrollable view.
* @param ctx
* @param primaryView Usually the "outer" scrollable view you want cooperating
* @param secondaryView Usually the "inner" scrollable view you want cooperating (null = ignore overscroll)
*/
public CooperativeScrollGestureListener(Context ctx, ViewGroup primaryView, ICoopInnerScrollableView secondaryView) {
mPrimaryView = primaryView;
mSecondaryView = secondaryView;
mGestureDetector = new GestureDetector(ctx, this);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (!isInGesture) {
isInGesture = true;
isScrollingVertical = (Math.abs(distanceY) > Math.abs(distanceX));
}
if (!isScrollingVertical) return false;
if (distanceY < 0 && null != mSecondaryView && mSecondaryView.isScrollableAtTop()) {
// VIEW GOING UP
mPrimaryView.requestDisallowInterceptTouchEvent(false);
} else if (distanceY > 0 && null != mSecondaryView && mSecondaryView.isScrollableAtBottom()) {
// VIEW GOING DOWN
mPrimaryView.requestDisallowInterceptTouchEvent(false);
} else {
// Pulling up but at bottom of secondary view OR pulling down and at top of secondary view
mPrimaryView.requestDisallowInterceptTouchEvent(true);
}
return false;
}
// This MUST return true for DOWN event to have this see subsequent events
@Override
public boolean onDown(MotionEvent e) {
isInGesture = false;
isScrollingVertical = true;
return true;
}
@Override
public void onShowPress(MotionEvent e) {
// nothing
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
isInGesture = false;
isScrollingVertical = false;
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// nothing
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
// ---------------------- methods -----------------------
/**
* Your Activity must call this in it's dispatchTouchEvent() override.
* @param ev
*/
public void dispatchTouchEvent(MotionEvent ev) {
mGestureDetector.onTouchEvent(ev);
}
/**
* The scrollable views (ScrollView, ListView, etc) should be wrapped in this interface to be
* generically handled by this listener. The operations done in these methods calls should
* not be computationally intensive since it would otherwise affect scrolling performance.
*/
public interface ICoopInnerScrollableView {
public boolean isScrollableAtTop();
public boolean isScrollableAtBottom();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment