带有mutl touch的Webkit iphone/ipad问题

带有mutl touch的Webkit iphone/ipad问题,iphone,ipad,safari,webkit,multi-touch,Iphone,Ipad,Safari,Webkit,Multi Touch,在UIWebView(支持多点触摸)中,我得到了一个包含两个div(div1和div2)的页面,每个div都注册了touchstart和touchend事件。每次他们接收触摸事件时,我都会转储以下内容: event.touchs:包含所有当前事件 触碰 event.targetTouches: 包含与 给定目标 event.changedTouches: 包含已触发 事件 考虑以下场景: 点击div1:event.touch包含div1 在不释放div1的情况下,点击div2:event.

在UIWebView(支持多点触摸)中,我得到了一个包含两个div(div1和div2)的页面,每个div都注册了touchstart和touchend事件。每次他们接收触摸事件时,我都会转储以下内容:

  • event.touchs:包含所有当前事件 触碰
  • event.targetTouches: 包含与 给定目标
  • event.changedTouches: 包含已触发 事件
考虑以下场景:

  • 点击div1:event.touch包含div1
  • 在不释放div1的情况下,点击div2:event.touchs包含div1和div2
  • 释放div2而不是div1:event.touchs为空,不应释放,因为仍在按div1。div1还收到了一个touchend事件,就好像它已被释放一样
  • 稍等片刻,仍然按下div1,它将收到一个新的touchstart事件,这没有意义,因为它从未发布过

所以基本上,当松开一根手指时,它的动作就像两个手指都被移除了一样。我错过什么了吗

是的,我也找到了这个。听起来应该是个bug,但我不确定

我发现在iOs webkit中实现各种多点触控功能最灵活的方法是在整个文档中捕获触控事件,即调用
document.addEventListener()
,以获取您感兴趣的各种触控事件

然后使用一些策略来找出触摸发生在哪个元素上。你可以:

  • 检查触摸屏的
    target
    属性以获取有关元素的一些信息。但是(另一个可能的bug?),您不能从这个属性中找到元素的ID,只能找到它的类,这对于区分使用同一个类的多个元素是没有好处的。检查的源以查看此操作

  • 将触摸屏的
    pageX
    pageY
    坐标与触摸屏可能涉及的每个元素(相对于文档)的尺寸和位置进行比较。例如,使用jQuery:

    var x = touch.pageX;
    var y = touch.pageY;
    var offset=$(element).offset();
    if (x >= offset.left && y >= offset.top && x < (offset.left + $(element).width()) && y < (offset.top + $(element).height())) 
    {
        // element was touched!
    }
    
    var x=touch.pageX;
    变量y=touch.pageY;
    var offset=$(元素).offset();
    如果(x>=offset.left&&y>=offset.top&&x<(offset.left+$(element.width())和&y<(offset.top+$(element.height())
    {
    //元素被触动了!
    }
    

使用此方法,所有触摸操作的行为都完全符合您的预期:)

感谢funkybro的评论,但不幸的是,在文档级别截取触摸事件时,我仍然可以观察到相同的错误行为。以下是正在发生的事情的线索:

finger 1 touches elem1:
20:44:00.130 onTouchStart: 
    touches len=1 (elem1)
    changedTouches len=1 (elem1)

finger 2 touches elem2 (finger 1 still presses elem1 and has not been released):
20:44:01.066  onTouchStart: 
    touches len=2 (elem1,elem2)
    changedTouches len=1 (elem2)

finger 2 being released (finger 1 still presses elem1 and has not been released):
this is where things begin to go wrong: we receive two touchend events consecutively for
both elem1 and elem2,even though finger 1 is still holding on elem1 and has never released it.
Also the event.touches array is empty for both events, which is wrong since elem1 is still
being pressed.
20:44:08.241  onTouchEnd: touches len=0
              changedTouches len=1 (elem1)

20:44:08.251  onTouchEnd: touches len=0
              changedTouches len=1 (elem2)

after 4 seconds in the same position (finger 1 pressed on elem1, finger 2 released),
we receive a new touchstart event, as if the system wanted to undo the previous mistake
and put things back into a consistent state.   
20:44:12.511  onTouchStart: 
    touches len=1 (elem1)
    changedTouches len=1 (elem1)

now releasing finger 1 from elem1, we receive the touchend event
20:44:14.751  onTouchEnd: 
    touches len=0 
    changedTouches len=1 (elem1)
编辑: 下面是一个代码示例,可以在Safari Mobile上运行,也可以在您自己的UIWebView设备(而不是模拟器)中运行


多点接触试验
分区广场{
位置:绝对位置;
宽度:80px;
高度:80px;
不透明度:0.5;
}
第1部分{
左:50px;
顶部:50px;
背景色:红色;
}
分区#elem2{
左:200px;
顶部:50px;
背景颜色:绿色;
}
text区域#记录器{
位置:绝对位置;
宽度100%;
身高:70%;
最高:30%;
背景颜色:灰色;
颜色:白色;
溢出:滚动;
}
功能日志(文本){
logger.value=logger.value+文本;
logger.scrollTop=logger.scrollHeight;
}
函数touchesDumpStr(touches,logPrefix){
var str=logPrefix+',count='+touchs.length+':';

对于(var i=0;i我有一个解决方案,但它不是最优的。在触发touchstart事件时跟踪touch.identifier。当您获得一个500ms的touchend事件设置间隔时。如果在此间隔期间另一个touchend和一个touchstart触发,请查看touchstart是否有一个现存的触摸标识符,并确定哪个手指被提起

当两个手指落下时,无法确定在第一次触摸结束时哪个手指已抬起。我查看了更改触摸的顺序,检查了touchstart事件的保存副本。我查看了故障之前的手势事件。剩余手指重复触摸启动的延迟取决于时间移动射击

如果这个bug破坏了你的多点触摸交互,那么在开发者文档中添加对事件序列的错误描述的反馈。

这个问题似乎在iOS 4.2中得到了解决
(我无法在带iOS 4.2.1的iPhone 4上复制它)

只是在iPod上偶然发现了同样的问题。我使用JavaScript,所以问题似乎相当基本(我们方面的错误或误解;-)是的,我很惊讶遇到这样一个问题,因为这是一个相当大的问题,在这种情况下,多点触摸几乎是不可用的。希望我们错过了什么…我想我遇到了同样的问题?你能确认吗?我来这里是因为我有同样的问题,我在iPad上使用PhoneGap/JavaScript。一个div的ontouchend似乎触发了ontouchend ev该div的元素加上另一个不相关的div。理想情况下,这应该是对原始答案的添加,或者是对我的评论的响应,而不是答案本身。我不太理解您的调试,但听起来好像每个元素都附加了侦听器,这就是导致您观察到的行为的原因。您可以粘贴吗将实际代码的相关片段缩短到您的问题中?在上面的代码示例中,我还尝试覆盖整个屏幕的透明div,以减少接收到的touchend事件的数量。但只要抬起一根手指,event.touch就会像抬起两根手指一样清空…看起来像是一个绝望的案例。更多细节我注意到:在触发2个touchend事件后,e.touch.length为0。如果,如您所述,再次按下elem1上的finger 1。touch.identifier与fi相同
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Multi-touch test</title>
    <style type="text/css">
        div.square {
            position:absolute;
            width:80px;
            height:80px;
            opacity:0.5;
        }
        div#elem1 {
            left:50px;
            top:50px;
            background-color:red;
        }
        div#elem2 {
            left:200px;
            top:50px;
            background-color:green;
        }
        textarea#logger {
            position:absolute;
            width100%;
            height:70%;
            top:30%;
            background-color:grey;
            color:white;
            overflow: scroll;
        }
    </style>

    <script type="text/javascript">
    function log(text) {
        logger.value = logger.value + text;
        logger.scrollTop = logger.scrollHeight;
    }

    function touchesDumpStr(touches,logPrefix) {
        var str = logPrefix + ', count=' + touches.length + ':';
        for (var i=0; i<touches.length; ++i) {
            if (typeof touches[i].target.customName != 'undefined') {
                str += touches[i].target.customName +' ';
            }
        }
        str += '\n';
        return str;
    }

    function onTouchStart(e) {
        log('onTouchStart\n');
        log(touchesDumpStr(e.touches, 'touches'));
        log(touchesDumpStr(e.targetTouches, 'targetTouches'));
        log(touchesDumpStr(e.changedTouches, 'changedTouches'));
        for (var i=0; i<e.changedTouches.length; ++i) {
            e.changedTouches[i].target.style.opacity=1.0;
        }
        e.preventDefault();
    }

    function onTouchEnd(e) {
        log('onTouchEnd\n');
        log(touchesDumpStr(e.touches, 'touches'));
        log(touchesDumpStr(e.targetTouches, 'targetTouches'));
        log(touchesDumpStr(e.changedTouches, 'changedTouches'));
        for (var i=0; i<e.changedTouches.length; ++i) {
            e.changedTouches[i].target.style.opacity=0.5;
        }
        e.preventDefault();
    }

    var logger;
    function init() {
        logger = document.getElementById('logger');
        document.getElementById('elem1').customName='elem1';
        document.getElementById('elem2').customName='elem2';
        document.addEventListener("touchstart", onTouchStart, false);
        document.addEventListener("touchend", onTouchEnd, false);   
    }
    </script>
</head>
<body onload="init();">
    <div class="square" id="elem1"></div>
    <div class="square" id="elem2"></div>
    <textarea id="logger" rows="10" cols="45" readonly></textarea>
</body>
</html>