14

我正在编写一个应用程序,该应用程序涉及使用手指或最终使用手写笔在屏幕上书写。我有那部分工作。在 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 的代码尚未发布,是吗?)我已经搜索了查询指针当前状态的方法,所以我可以有一个计时器捕捉变化,直到指针越过阈值。不能 在没有相应的移动事件的情况下,找不到任何获取指针坐标的方法。没有任何效果。有人对此有所了解,或者有任何想法或解决方法吗?谢谢你。

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

4

3 回答 3

25

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

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

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

(对我们来说)更能说明问题的是,当更改 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设置为较小的值将增加敲击被解释为笔划的机会。

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

于 2013-03-14T05:14:18.577 回答
4

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

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)

于 2012-01-13T14:43:46.827 回答
1

扩展视图类。

覆盖没有“@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);
}
于 2018-08-16T08:37:33.460 回答