使用 GestureDetector onScroll 实现滚动延迟

发布于 2024-11-30 15:05:34 字数 493 浏览 1 评论 0原文

我使用 GestureDetector 在自定义 View 内实现滚动。我的实现基于此:惯性滚动和边缘阻力/回弹

我注意到滚动开始之前有短暂的停顿:我检查了 onScroll 消息并注意到第一个只有在手指进行较大移动后才会到达,这会在滚动开始时导致明显的滞后。之后滚动就顺畅了。

似乎 GestureDetector 仅在运动事件之间的最小距离之后才开始发送 onScroll 消息,以确保手势不是长按或点击(顺便说一句,我设置了 setIsLongpressEnabled(false) ))。

有没有办法改变这种行为并创建平滑的滚动,而无需使用低级触摸事件实现自定义滚动手势?

I use GestureDetector to implement scrolling inside a custom View. My implementation is based on this: Smooth scrolling with inertia and edge resistance/snapback

I noticed a short pause before the scrolling starts: I examined the onScroll messages and noticed that the first one arrives only after a larger movement of a finger, which causes noticable lag at the beginning of the scrolling. After that the scrolling is smooth.

It seems GestureDetector starts sending onScroll messages only after a minimal distance between the motionevents to make sure the gesture is not a longtap or tap (btw I set setIsLongpressEnabled(false)).

Is there any way to change this behaviour and create a smooth scroll without implementing a custom scroll gesture using low level touch events?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦言归人 2024-12-07 15:05:34

答案是否定的,您必须创建自己的GestureDetector。如果你查看Android源代码(GestureDetector.java) 第 524 到 540 行用于检测“触摸” slop”用于单次水龙头。具体来说,第 528 行阻止调用 onScroll 事件,直到移动超出触摸斜面(从视图配置中拉出)。您无法更改视图配置,并且斜率硬编码为 16 像素。这是导致您看到的滞后的半径。

The answer is no, you have to create your own GestureDetector. If you look at the Android source code (GestureDetector.java) lines 524 to 540 are use to detect the "touch slop" for a single tap. Specifically line 528 prevents the onScroll event from being called until the movement is outside the touch slop (which is pulled from the view configuration). You cannot change the view configuration and the slop is hard coded at 16 pixels. This is the radius that causes the lag that you are seeing.

生死何惧 2024-12-07 15:05:34

您可以使用反射将 mTouchSlopSquareGestureDetector.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< /a>

    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);
        }
    }

You can use reflection to change mTouchSlopSquare from 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);
        }
    }

Also, here is the method to change the slop for the 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);
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文