Last active
December 18, 2015 02:39
-
-
Save willbailey/f2d9b569695a8f0a5e7b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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