【问题标题】:When does a touchesBegan become a touchesMoved?touchesBegan 什么时候变成 touchesMoved?
【发布时间】:2010-11-10 11:49:09
【问题描述】:

当您在 iPhone 触摸屏上拖动手指时,它会以正常的 60Hz 频率生成 touchesMoved 事件。

但是,从最初的 touchesBegan 事件到第一个 touchesMoved 的转换不太明显:有时设备会等待一段时间。

它还在等什么?更大的时间/距离增量?更多的触动融入活动?

有人知道吗?

重要的是,这种延迟不会发生在随后的手指上,这使第一次触摸处于明显的劣势。对于需要精确输入的应用(例如游戏和乐器)来说,这是一个非常不对称的坏消息。

查看此错误/现象的实际效果

  1. 慢慢向右拖动 iPhone 屏幕解锁滑块。注意突然的跳跃并注意如果您将另一根手指放在屏幕上的其他任何地方,它不会发生

  2. 在任意数量的 3D 游戏中尝试“爬行”穿过狭窄的桥。令人沮丧!

  3. 尝试双虚拟摇杆游戏并注意效果会有所缓解,因为您必须永不停止任何一种触摸操作,从而消除不愉快的感觉。

8 个月前应该将此记录为错误。

【问题讨论】:

    标签: iphone uikit multi-touch


    【解决方案1】:

    在触发 touchesBegan 事件后,UIKit 会查找手指触摸的位置移动,当手指的 x/y 发生变化时,它会转换为 touchMoved 事件,直到手指抬起并触发 touchesEnded 事件。

    如果手指被按住在一个地方,它不会触发 touchesMoved 事件,直到有移动。

    我正在构建一个应用程序,您必须在其中基于 touchesMoved 进行绘制,它确实会每隔一段时间发生一次,但它足够快,可以提供平滑的绘图外观。由于它是一个事件并且隐藏在 SDK 中,因此您可能必须在您的场景中进行一些测试以查看它的响应速度,具体取决于其他操作或事件,它可能会因使用情况而异。根据我的经验,它在几毫秒的移动范围内,屏幕上大约有 2-3k 个其他精灵。

    绘图确实从 touchesBegan 事件开始,因此设置了第一个位置,然后它链接到 touhesMoved 并以 touchesEnd 结束。我将所有事件都用于拖动操作,因此在这种情况下,初始移动在感知上可能不那么滞后。

    要在您的应用中进行测试,您可以在每个事件上加上一个时间戳,如果它对您的设计至关重要,并制定出某种缓和方式。

    http://developer.apple.com/IPhone/library/documentation/UIKit/Reference/UIResponder_Class/Reference/Reference.html#//apple_ref/occ/instm/UIResponder/touchesMoved:withEvent:

    【讨论】:

    • 我已经做到了。对于精细移动,第一个“移动”可能比随后移动的对慢得多。尝试绘制一些连接的线段。第一段应该更长。差异是微妙的,我认为我的应用程序正在放大效果(它模拟转盘)。除非有较低级别的界面,否则我只需要最小化效果。
    • 是的,我正在使用一些插值和外推来实现网络效应(点之间的缓和和一些预测)。但是在本地你可能也需要这个。这取决于您的应用,但请记住,它仍然是一个缓慢的处理器和一台旧电脑,所以如果您有大量图形和事件,就会有延迟。
    • 对我来说这种行为是一个错误,所以我会记录下来。我的应用自然会平滑不连续性,但它当然会受益于 UIKit 提供的更高质量的多点触控输入。
    【解决方案2】:

    我不认为这是一个错误,它更像是一个缺失的功能。

    通常,这是为了过滤掉意外的微动作,这些动作会在用户无意中将点击或长按转换为幻灯片。

    这并不是什么新鲜事,它一直都存在,例如,在基于指针的 GUI 中双击有几个像素的容差 - 甚至在开始拖动之前也有相同的容差,因为用户有时会在他们不经意间拖动只是想点击。尝试在桌面(OSX 或 Windows)上缓慢移动项目以查看它。

    缺少的功能是它似乎不可配置。

    一个想法:是否可以在touchesBegan 上进入定时循环,定期检查触摸的locationInView:

    【讨论】:

    • 不,不可能使用带 locationInView 的计时器,因为它返回的点会在调用 touchesMoved: 的同时更新。这意味着您永远不会在 touchesMoved 之前获得新的 locationInView。
    • 此外,在将 touchesMoved 事件转发到响应者链之前,似乎即使应用程序对象本身也没有收到新的触摸事件 - 这意味着低级操作系统本身是造成延迟 touchesMoved 的原因事件。所以在 Apple 让我们改变它之前可能无法解决。
    【解决方案3】:

    我不代表任何形式的官方答案,但 touchesBegan->touchesMoved 的持续时间比 touchesMoved->touchesMoved 更长是有道理的。如果每次 touchesBegan 都伴随着一堆意外的 touchesMoved 事件,开发人员会很沮丧。苹果一定已经(通过实验)确定了触摸变成拖拽的距离。一旦 touchesMoved 开始,就不需要再执行这个测试了,因为直到下一次 touchesUp 之前的每个点都保证是 touchesMoved。

    这似乎是您在原始帖子 Rythmic Fistman 中所说的,我只是想详细说明一下,并表示我同意您的推理。这意味着,如果您要计算某种“拖动速度”,则需要使用行进距离作为一个因素,而不是取决于更新计时器的频率(无论如何这是更好的做法)。

    【讨论】:

    • 如果唯一合乎逻辑且可能的事情是拖动意图(例如,请参阅 UISlider),那么等待 0.25 秒直到应用程序收到有关拖动意图的报告是没有任何智能的。 Apple 必须为我们提供禁用任何延迟的选项。
    • 正是@Thanks,还有@Kai,也许延迟行为对于粗略输入来说是可取的,但您需要能够将其关闭。它也不适用于其他四个触摸。你如何证明这一点?
    【解决方案4】:

    它正在等待第一步。 这就是操作系统区分拖动和点击的方式。拖动后,所有新通知都会被 touchesMoved。

    这也是您应该编写代码以在修饰事件时执行的原因。

    【讨论】:

    • 我很好奇什么是“第一步”。你的观点“所有新通知在拖动后都是 touchesMoved”是错误的:如果你用不同的手指点击,你当然会得到一个 touchesBegan 事件。然而,这些进一步的触摸似乎更快地转换为 touchesMoved 事件。好奇的。回复:“修饰”事件建议,我正在实现一些比一般按钮或复选框更具触感的东西,所以不会削减它。
    • 我可以确认这一点。这在 iPhone 操作系统中是一个非常大的问题。
    【解决方案5】:

    目前,当其他手指触摸屏幕时,touchesBegan 和 touchesMoved 之间的这种“延迟”也会出现。不幸的是,似乎尚不存在禁用它的选项。我也是一名音乐应用开发者(和播放器),我觉得这种行为很烦人。

    【讨论】:

    • 也许有一个使用 UIScrollView 的 delaysContentTouches 属性的解决方法,但我还不能让它工作。
    猜你喜欢
    • 2011-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多