Skip to content

Instantly share code, notes, and snippets.

@willbailey
Last active December 18, 2015 02:39
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 willbailey/f2d9b569695a8f0a5e7b to your computer and use it in GitHub Desktop.
Save willbailey/f2d9b569695a8f0a5e7b to your computer and use it in GitHub Desktop.
package im.wsb.example
import java.lang.reflect.Field;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.ListView;
public class ProperTouchSlopListView extends ListView {
private static final int X_DRAGGING_RANGE = 90;
private final int mDefaultTouchSlop;
private Field mTouchSlopField;
private boolean mClampingX;
private boolean mClampingY;
private MotionEvent mDownEvent;
private boolean mReflectionIsBroken;
public ProperTouchSlopListView(Context context) {
this(context, null);
}
public ProperTouchSlopListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ProperTouchSlopListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDefaultTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
try {
mTouchSlopField = AbsListView.class.getDeclaredField("mTouchSlop");
mTouchSlopField.setAccessible(true);
} catch (NoSuchFieldException e) {
mReflectionIsBroken = true;
}
}
private void setAllowBuiltinInterceptBehavior(boolean allow) {
if (mTouchSlopField == null) {
return;
}
try {
mTouchSlopField.set(this, allow ? mDefaultTouchSlop : Integer.MAX_VALUE);
} catch (IllegalAccessException e) {
mReflectionIsBroken = true;
}
}
private void checkClamping(MotionEvent down, MotionEvent current) {
float dX = down.getX() - current.getX();
float dY = down.getY() - current.getY();
if (mClampingY || mClampingX) {
return;
}
double distance = Math.sqrt(dX * dX + dY * dY);
boolean exitedSlop = distance > mDefaultTouchSlop;
double angle = Math.toDegrees(Math.atan(Math.abs(dY / dX)));
if (exitedSlop) {
if (angle <= X_DRAGGING_RANGE / 2) {
mClampingX = true;
} else {
mClampingY = true;
}
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mClampingX = false;
mClampingY = false;
mDownEvent = MotionEvent.obtain(ev);
break;
case MotionEvent.ACTION_MOVE:
checkClamping(mDownEvent, ev);
break;
}
setAllowBuiltinInterceptBehavior(mReflectionIsBroken || mClampingY);
return super.onInterceptTouchEvent(ev);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment