多点触控:只有在触摸移动发生时才会触发touchend事件。

12

当我的 JavaScript 应用在 iOS 设备上访问时(以及后来的 Android 设备),我希望添加一些多点触控功能。

我想提供一个类似 Shift 键的功能:用户可以用一根手指按住屏幕上的一个按钮,而在这个按钮被按住期间,对于屏幕上其余区域的轻触操作的行为与经典的轻触略有不同。

我遇到的问题是,除非第一只按住 Shift 键的手指发生了 touchmove 事件,否则我收不到轻触手指的任何 touchend 事件。

由于屏幕非常灵敏,touchmove 事件很容易被触发,在大多数情况下一切都正常工作。

但是当用户的手指稍微静止一点时,会导致轻触无法被检测到,直到用户稍微移动手指为止。这会导致轻触与屏幕上出现的动作之间存在变量 "延迟"(如果用户非常冷静,延迟可能会持续几秒钟)。

我的猜想是,这种延迟会导致用户再次轻触屏幕,从而再次触发动作,这正是我不希望发生的事情!

您可以在 iPad/iPhone 上使用此链接进行测试:http://jsfiddle.net/jdeXH/8/

尝试在红色区域上轻触的同时,在青色区域上用手指保持非常静止的状态,使整个页面始终保持绿色。

这种行为是否可以预期?有没有已知的解决方法?我本来期望当手指从屏幕上移开时,touchend 事件会立即被触发。

我使用的 iOS 版本是 5.1.1(iPad1 和 iPhone4S)

编辑:找到一个类似的问题 Multitouch touchEvents not triggered as they should on Safari Mobile


这里似乎有一个类似的问题:http://stackoverflow.com/questions/8839333/multitouch-touchevents-not-triggered-as-they-should-on-safari-mobile - Louis
很棒的问题。我希望有人能回答这个问题。我在 iPhone 4 和 iPad 3 上遇到了完全相同的行为。对于我的项目,我将事件侦听器附加到单个包含元素上。这似乎(也许只是我的想象?)稍微提高了性能,但问题肯定存在,而且似乎相当零散:http://jsfiddle.net/seeligd/DwNd9/59/ - pho79
@pho79,我同意你的版本在大多数情况下感觉更加响应,但遗憾的是仍然不完美。很难相信人们在Web应用程序上不使用多点触控已经足够避免遇到这个问题了。 - Louis
@zaf 不好意思,我没能找到解决方法,所以我只是暂时修改了我的应用程序设计。不过,如果没有可行的解决方案,那么在响应式 Web 应用程序中使用 真正的 多点触控似乎对我来说毫无意义。我仍然对任何人可能有的想法感兴趣... - Louis
@dridri 是的,我刚刚花了一整天来调试这个问题。真是让人头疼。现在是时候改变设计了... - zaf
4个回答

3

看起来这个bug困扰了一些人比我更多, 他们直接向苹果公司报告了这个bug,几年后在iOS6中修复了 :)


1

好的,这是一个头疼的问题。是的,有两个已知的问题。首先,Safari有时候不会触发touchEnd事件,除非在某个地方有touchMove,即使touchMove并没有做太多事情。

其次,Chrome Mobile也是一种美妙的体验,因为在许多Android设备上,无论你做什么,touchEnd事件都不会触发。所以根据我的经验:

  • 实现一个touchStart事件,注册起始坐标等
  • 实现一个touchMove事件,与touchEnd完全相同,但确保回调函数不会多次触发。使用在更高范围内定义的布尔标志或类似的东西。
  • 实现正常的touchEnd事件,只有在touchMove尚未触发回调的情况下才应触发,使用在更高范围内定义的相同布尔标志。

0

看起来你遇到了一些无法避免的情况,只能使用有缺陷的技巧。你正在创建一个UI功能,它还不是“常规”的,但似乎很有前途(我喜欢...我喜欢)。在这个技术点上,你需要问自己的问题是:“如何强制用户滑动手指才能按住Shift键”。

在一个好的设计师的帮助下,我认为你可以创建一个类似于翻转开关的滑动切换按钮...用户必须拖动并保持开关处于“打开”状态。松开后,开关会弹回到“关闭”位置。我提到了设计师,因为按钮需要看起来像是有反应的。也许一些评论可以有所创意。


0

好的,我已经实现了这个解决方案,看起来它能够正常工作。

//Initialize the tap touch
function ManageTapTouch() {
    this.__enabled__ = false;
}

ManageTapTouch.prototype.init = function(){
    $("#hold").bind('touchstart', $.proxy(this.__enable__, this));
    $('#hold').bind('touchend', $.proxy(this.__disable__, this));
    $('#tap').bind('touchstart',  $.proxy(this.__changeColorOnHold__, this));
    $('#tap').bind('touchend',  $.proxy(this.__changeColorOnOut__, this));
};
ManageTapTouch.prototype.__enable__ = function(event) {
    this.__enabled__ = true;
};
ManageTapTouch.prototype.__disable__ = function(event) {
    this.__enabled__ = false;
    $('body').css('background-color', 'blue'); 
};
ManageTapTouch.prototype.__changeColorOnHold__ = function(event) {
    if (this.__enabled__){
        $('body').css('background-color', 'black');
    }
};
ManageTapTouch.prototype.__changeColorOnOut__ = function(event) {
    $('body').css('background-color', 'blue');
};

new ManageTapTouch().init();

您可以在此处查看其运行情况:http://jsfiddle.net/Tb6t6/15/

另外,您还可以尝试使用多点触控在 iPhone 上进行操作:event.originalEvent.touches[0].pageXevent.originalEvent.touches[0].pageY,其中索引是屏幕上的手指,事件是在TouchStart上触发的。通过这些主题,您可以实现自己的版本或使用我在此提出的版本。


很抱歉,我不明白你的回答是如何解决问题的。代码大致上做了相同的事情,但当我从屏幕上移开手指时仍然会出现一些“卡顿”的情况。我是否漏掉了什么? - Louis
你遇到了什么样的延迟问题?具体是哪些功能无法正常工作?你使用的设备是什么?我在Chrome浏览器(Android 4.0)和iPhone上尝试过,使用的是HTC Desire S,一切都正常!touchEnd事件总是被调用。 - droidpl
我不知道这在其他设备上的表现如何,因为我只对此JavaScript应用程序中的iOS设备感兴趣。当然,touchend总是被调用的,但不一定是立即调用,即只有在另一个事件(通常是touchmove)触发后才会调用。这就导致了手指实际从屏幕上移开和touchend触发之间的“延迟”。在您的演示中,它会导致背景保持黑色,即使触摸红色div的手指已经离开屏幕。事实上,直到您移动(稍微)/删除触摸青色div的第一个手指,背景才会保持黑色。 - Louis
好的,我检查了一下。你的问题与焦点有关。当你选择一个div时,如果你的焦点不在div中心而是在溢出层中心,那么你的事件就不会显示。我的意思是,在iOs导航器上进行捏合事件以实现缩放功能,直到你重新将焦点恢复到所选的div之前,事件才会被触发。尝试管理捏合事件并在执行后重新聚焦div或使用device-width元参数更改窗口行为。 - droidpl
实际上,在我的fiddle中,禁用iOS提供缩放功能的事件是通过返回false来实现的。尝试重新聚焦div确实值得一试,但我仍然会遇到随机延迟,如果您成功使其正常工作,也许您可以提供一些代码。 - Louis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接