我使用GestureDetector
在自定义View
内实现滚动。我的实现基于:Smooth scrolling with inertia and edge resistance/snapback
我注意到在滚动开始之前有一个短暂的停顿:我检查了onScroll
消息并注意到第一个消息仅在手指移动较大时才到达,这会在滚动开始时引起明显的延迟。之后滚动顺利。
似乎GestureDetector
仅在动作事件之间的最小距离之后开始发送onScroll
消息,以确保手势不是长按或轻击(顺便说一下,我设置setIsLongpressEnabled(false)
)。
有没有办法更改此行为并创建平滑滚动而不使用低级别触摸事件实现自定义滚动手势?
答案 0 :(得分:10)
答案是否定的,您必须创建自己的GestureDetector
。如果您查看Android源代码(GestureDetector.java),则使用行524到540来检测单击的“触摸slop”。具体地,线528防止onScroll
事件被调用,直到移动位于触摸斜面(从视图配置拉出)之外。您无法更改视图配置,并且slop硬编码为16像素。这是导致您看到滞后的半径。
答案 1 :(得分:0)
您可以使用反射将 mTouchSlopSquare
从 GestureDetector.java 更改为
public static void setGestureDetectorTouchSlop(GestureDetector gestureDetector, int value) {
try {
Field f_mTouchSlopSquare = GestureDetector.class.getDeclaredField("mTouchSlopSquare");
f_mTouchSlopSquare.setAccessible(true);
f_mTouchSlopSquare.setInt(gestureDetector, value * value);
} catch (NoSuchFieldException | IllegalAccessException | NullPointerException e) {
Log.w(TAG, gestureDetector.toString(), e);
}
}
此外,这里是更改 GestureDetectorCompat.java 斜率的方法
public static void setGestureDetectorTouchSlop(GestureDetectorCompat gestureDetector, int value) {
try {
Field f_mImpl = GestureDetectorCompat.class.getDeclaredField("mImpl");
f_mImpl.setAccessible(true);
Object mImpl = f_mImpl.get(gestureDetector);
if (mImpl == null) {
Log.w(TAG, f_mImpl + " is null");
return;
}
Class<?> c_GDCIJellybeanMr2 = null;
Class<?> c_GDCIBase = null;
try {
c_GDCIJellybeanMr2 = Class.forName(GestureDetectorCompat.class.getName() + "$GestureDetectorCompatImplJellybeanMr2");
c_GDCIBase = Class.forName(GestureDetectorCompat.class.getName() + "$GestureDetectorCompatImplBase");
} catch (ClassNotFoundException ignored) {
}
if (c_GDCIJellybeanMr2 != null && c_GDCIJellybeanMr2.isInstance(mImpl)) {
Field f_mDetector = c_GDCIJellybeanMr2.getDeclaredField("mDetector");
f_mDetector.setAccessible(true);
Object mDetector = f_mDetector.get(mImpl);
if (mDetector instanceof GestureDetector)
setGestureDetectorTouchSlop((GestureDetector) mDetector, value);
} else if (c_GDCIBase != null) {
Field f_mTouchSlopSquare = c_GDCIBase.getDeclaredField("mTouchSlopSquare");
f_mTouchSlopSquare.setAccessible(true);
f_mTouchSlopSquare.setInt(mImpl, value * value);
} else {
Log.w(TAG, "not handled: " + mImpl.getClass().toString());
}
} catch (NoSuchFieldException | IllegalAccessException | NullPointerException e) {
Log.w(TAG, gestureDetector.getClass().toString(), e);
}
}