【问题标题】:Android ACTION_MOVE ThresholdAndroid ACTION_MOVE 阈值
【发布时间】:2011-10-10 17:37:35
【问题描述】:

我正在编写一个应用程序,其中涉及使用手指或最终使用手写笔在屏幕上书写。我有那部分工作。在 ACTION_DOWN 上,开始绘制;在 ACTION_MOVE 上,添加线段;在 ACTION_UP 上,终点线。

问题在于,在 ACTION_DOWN 之后,显然指针需要从它开始的位置移动 10 多个像素(基本上是围绕起点的 20x20 框)才能开始发送 ACTION_MOVE 事件。离开盒子后,移动事件都相当准确。 (我通过测试找出了 10 像素的东西。)由于这是用于书写或绘图的,因此 10 像素是相当大的损失:取决于您尝试书写的大小,您可能会丢失第一个字母或两个。我找不到任何关于它的信息——只有一两个论坛上的几个帖子,比如http://android.modaco.com/topic/339694-touch-input-problem-not-detecting-very-small-movements/page_pid_1701028#entry1701028。它似乎出现在某些设备或系统上,而不是其他设备或系统上。但是,没有关于如何摆脱它的想法。

我使用的是带有 Android 3.1 的 Galaxy Tab 10.1。我已经尝试了几种不同的方法来尝试摆脱它:我尝试将事件的坐标设置为其他东西,看看我是否可以欺骗它认为光标在不同的位置;我尝试通过更改坐标重新调度事件(我的处理程序对新点做出反应,但仍然没有对 10 像素半径内的移动做出响应。)我已经在源代码中搜索了对效果的任何引用,并没有找到(尽管我认为它来自不同版本的 Android - 3.1 的代码尚未发布,是吗?)我已经搜索了查询指针当前状态的方法,所以我可以有一个计时器捕捉变化,直到指针越过阈值。如果没有相应的移动事件,找不到任何获取指针坐标的方法。没有任何效果。有人对此有所了解,或者有任何想法或解决方法吗?谢谢。

-- 更新:拖放事件显示相同的阈值。

【问题讨论】:

    标签: android touch move ontouchlistener threshold


    【解决方案1】:

    问题出在 View https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/View.java 类的第 6549 行

    if (!pointInView(x, y, mTouchSlop)) {...}
    
     /**
     * Utility method to determine whether the given point, in local coordinates,
     * is inside the view, where the area of the view is expanded by the slop factor.
     * This method is called while processing touch-move events to determine if the event
     * is still within the view.
     */
    private boolean pointInView(float localX, float localY, float slop) {
        return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
                localY < ((mBottom - mTop) + slop);
    }
    

    mTouchSlop 在构造函数中设置

    mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    

    您可以扩展 View 并将 mTouchSlop 设置为零。我没有看到其他设置 mTouchSlop 的方法。没有像getApplicationContext.setScaledTouchSlop(int n)这样的功能。

    【讨论】:

    • 感谢您的回答 - 这看起来确实像有问题的价值,所以至少我知道现在这该死的东西叫什么了。不幸的是,虽然我可以使用反射来更改值,但它没有效果。我什至尝试为所有视图的父母更改它 - 不走运。让它变大也无济于事。我的猜测是,可能在事件到达我的视图之前应用了 TouchSlop 值。它似乎被硬编码在系统源代码中的 config.xml 文件中,我不知道是否有办法在不重建整个东西的情况下更改它。感谢您的帮助。
    • 如果您正在查看回收站视图,则有这样的功能。 recyclerView.setScrollingTouchSlop(TOUCH_SLOP_PAGING) developer.android.com/reference/android/support/v7/widget/…
    【解决方案2】:

    我部分同意@passsy 的帖子,但得出不同的结论。首先如前所述,mTouchSlop 是我们感兴趣的值,并通过ViewConfiguration.get(context).getScaledTouchSlop(); 公开

    如果您检查 ViewConfiguraton 的 Android 源代码,则 TOUCH_SLOP 的默认值为 8dip,但 cmets 提到此值只是一个备用值,并且实际值是在构建特定设备的 Android 操作系统时定义的。 (它可能大于或小于此值。它似乎适用于 Galaxy Tab 设备)

    更具体的代码示例,mTouchSlop 值是在 View 初始化时从 ViewConfiguration 读取的,但该值只能在 onTouchEvent 方法中访问。如果您扩展 View 并覆盖此方法(不调用 super),则 mTouchSlopView 类中的行为不再相关。

    更能说明问题的是(对我们而言)当更改 Android 设置以在屏幕上覆盖触摸事件时,带有小拖动的触摸不会注册为运动事件,这一点突出显示了 Android 操作系统的十字准线确实如此不动。由此我们得出的结论是,最小拖动距离在操作系统级别被强制执行,您的应用程序永远不会意识到小于 TOUCH_SLOP 值的拖动事件。您还应该注意,不应直接使用 TOUCH_SLOP,并且 API 不推荐使用 getTouchSlop 方法并建议使用考虑设备屏幕尺寸和像素密度的 getScaledTouchSlop。这样做的副作用是,在不同设备上感知的实际最小行程长度可能会有所不同。例如,在 Galaxy Tab 2.0 7.0" 上,感觉我们能够使用与在 Galaxy Tab 2.0 10.1" 上运行时相同的代码库绘制更短的最小笔划

    您还应该知道(如果您找到了更改此值的方法),此值决定了 Android 系统如何区分轻击和敲击。也就是说,如果您点击屏幕,但在执行点击时手指略有移动,如果移动小于 TOUCH_SLOP 将被解释为轻击,但如果移动超过 则被解释为中风TOUCH_SLOP。因此,将 TOUCH_SLOP 设置为较小的值会增加点击被解释为笔划的机会。

    我们自己的结论是,这个最小距离在实践中是无法改变的,是我们需要忍受的。

    【讨论】:

      【解决方案3】:

      扩展视图类。

      覆盖没有“@Override”注释的pointInView方法并设置touchSlop = 0:

      public boolean pointInView(float localX, float localY, float slop) {
          slop = 0;
          return localX >= -slop && localY >= -slop && localX < (getWidth() + slop) &&
                  localY < (getBottom() + slop);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多