Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save imminent/671948099b8162115f83112213dad259 to your computer and use it in GitHub Desktop.
Save imminent/671948099b8162115f83112213dad259 to your computer and use it in GitHub Desktop.
A custom NestedScrollView that delays vertical scrolling, providing more leniency to horizontal scrolling
import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.widget.NestedScrollView;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
/**
* Increases the vertical touch threshold before we are locked into vertical scrolling
*/
public class HorizontalFavoringNestedScrollView extends NestedScrollView {
private static final int INVALID_POINTER = -1;
private int mLastMotionY;
private int mTouchSlop;
private int mActivePointerId;
public HorizontalFavoringNestedScrollView(Context context) {
super(context);
init();
}
public HorizontalFavoringNestedScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HorizontalFavoringNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Gives extra preference to horizontal scrolling
switch (MotionEventCompat.getActionMasked(ev)) {
case MotionEvent.ACTION_MOVE: {
final int activePointerId = mActivePointerId;
if (activePointerId == INVALID_POINTER) {
// If we don't have a valid id, the touch down wasn't on content.
break;
}
final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
if (pointerIndex == -1) {
break;
}
final int x = (int) MotionEventCompat.getX(ev, pointerIndex);
final int y = (int) MotionEventCompat.getY(ev, pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
if (yDiff < mTouchSlop) {
return false;
}
break;
}
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
if (!inChild((int) ev.getX(), y)) {
break;
}
/*
* Remember location of down touch.
* ACTION_DOWN always refers to pointer index 0.
*/
mLastMotionY = y;
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
break;
}
case MotionEvent.ACTION_UP: {
/* Release the drag */
mActivePointerId = INVALID_POINTER;
break;
}
}
return super.onInterceptTouchEvent(ev);
}
private void init() {
mTouchSlop = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, 40f, getResources().getDisplayMetrics());
}
private boolean inChild(int x, int y) {
if (getChildCount() > 0) {
final int scrollY = getScrollY();
final View child = getChildAt(0);
return !(y < child.getTop() - scrollY
|| y >= child.getBottom() - scrollY
|| x < child.getLeft()
|| x >= child.getRight());
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment