touchend事件在安卓系统上无法正常工作。

32

我刚开始学习在 Android 上进行基础的移动 Web 开发,并编写了一个测试脚本来研究触摸事件。我在 Android 模拟器上运行了以下代码,但 touchend 事件从未被触发。请问有人知道为什么吗?

我已经尝试了三个版本的模拟器(1.6、2.1 和 2.2),它们都是同样的行为。

非常感谢您提供的任何帮助。

祝好, Colm

编辑 - 我还尝试使用 XUI 框架,但遇到了相同的问题,因此我猜测我对这些东西的工作原理存在根本性的误解......

地图测试

    <meta name="description" content="" />
    <meta name="keywords" content="" />
    <meta name="language" content="english" />

    <meta name="viewport" content="minimum-scale=1.0,
                                   width=device-width,
                                   height=device-height,
                                   user-scalable=no">
    <script type="text/javascript">
        window.onload = function(){
            document.body.appendChild(
                    document.createTextNode("w: " + screen.width + " x " + "h : " +screen.height)
            );
           attachTouchEvents();
        }
        function attachTouchEvents() {
            console = document.getElementById("console");
            var map = document.getElementById("map");
            map.addEventListener ('touchstart', function (event) {
                event.preventDefault();
                var touch = event.touches[0];
                document.getElementById("touchCoord").innerHTML = "S : " + touch.pageX + " " + touch.pageY;
                document.getElementById("touchEvent").innerHTML = "Touch Start";
            }, false);

            map.addEventListener ('touchmove', function (event) {
                event.preventDefault();
                var touch = event.touches[0];
                document.getElementById("touchCoord").innerHTML = "M : " + touch.pageX + " " + touch.pageY;
                document.getElementById("touchEvent").innerHTML = "Touch Move";
            }, false);

            map.addEventListener ('touchend', function (event) {
                var touch = event.touches[0];
                document.getElementById("touchCoord").innerHTML = "E : " + touch.pageX + " " + touch.pageY;
                document.getElementById("touchEvent").innerHTML = "Touch End";
                event.preventDefault();
            }, false);
            console.innerHTML = "event attached";
        }
    </script>
    <style type="text/css">
        html, body {
            height:100%;
            width:100%;
            margin: 0;
            background-color:red;
        }
        #map {
            height: 300px;
            width: 300px;
            background-color:yellow;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <div id="touchCoord">Touch Coords</div>
    <div id="touchEvent">Touch Evnt</div>
    <div id="console">Console</div>

</body>


1
我不确定你是如何尝试做到这一点的。当你说你已经用模拟器尝试过了,你指的是什么?你是在运行一个Android应用程序(例如使用各种视图的“Activity”),还是使用Android浏览器访问网页?如果你正在编写一个实际的Android应用程序,请注意,“WebView”与“onTouchEvent”回调函数不兼容。它内置的大于屏幕的页面上滑动的系统会与“MotionEvent”发生冲突,因此你会得到不一致的行为。 - Steve Haley
我也在一个7英寸的安卓平板上遇到了这个问题,即 touchend 事件从不触发。请参阅 http://code.google.com/p/android/issues/detail?id=19827#makechanges。 - Steven de Salas
9个回答

31

14
这个漏洞在 Android 4.3 上也没有修复。 - BairDev
4
在4.4.2版本中遇到了同样的问题。 - Rhyono
当然,这会阻止原生滚动,因此您需要自己重新实现它。我最初的想法是在touchmove事件中使用“e.preventDefault()”(以使浏览器触发touchmove和touchend),然后手动触发touchmove事件,但似乎无法避免自己实现滚动/缩放... - lx222
自从两年前向Google提出此问题以来,该问题尚未得到解决。我建议我们告知用户切换到其他浏览器以获得更快速的网络体验。 - Question Overflow
4.4.4 也有这个问题。 - Petr Peller

21

这是如何正确使用它的方法。当手指触碰屏幕时,您需要捕获起始坐标x和y。当手指移动时,touchmove事件会更新结束点的x和y坐标。完成后,touchend事件会触发 - 但是是的,它没有一个touches数组,因此会出现javascript错误。这就是为什么我们只用它来捕获这是一个结束任务(手指离开屏幕),然后对其做出反应的原因。(在这种情况下,我发送了一个信息提示框。)

var gnStartX = 0;
var gnStartY = 0;
var gnEndX = 0;
var gnEndY = 0;

window.addEventListener('touchstart',function(event) {
  gnStartX = event.touches[0].pageX;
  gnStartY = event.touches[0].pageY;
},false);

window.addEventListener('touchmove',function(event) {
  gnEndX = event.touches[0].pageX;
  gnEndY = event.touches[0].pageY;
},false);

window.addEventListener('touchend',function(event) {
  alert('START (' + gnStartX + ', ' + gnStartY + ')   END (' + gnEndX + ', ' + gnEndY + ')');
},false);

8

这是一个网站开发项目,我正在构建一个可以利用触摸事件的网页。

我找到了问题所在。

touchend事件被触发时,event.touches[]数组为空,因此会抛出Javascript错误。虽然事件被触发了,但没有打印任何内容,因为我试图访问未定义的数据。仿真器浏览器似乎没有我找到的任何Javascript调试工具,甚至没有告诉我Javascript错误发生的时候,所以我花了一段时间才找到问题所在。


3

我曾经遇到同样的问题,后来绑定了'touchcancel'事件解决了它。经过一些测试,当'touchend'没有触发时,'touchcancel'事件就会被触发。

var onTouchEnd = function(){
  console.log("touch end");
}
document.addEventListener("touchend", onTouchEnd);
document.addEventListener("touchcancel", onTouchEnd);

我可以确认这适用于Android 5,找到了相同的解决方案。 - wessel

3

1
你可以使用changedTouches来获取已移除的手指列表。 - WORMSS

3
map.addEventListener ('touchend', function (event) {
    var touch = event.changeTouches[0];
    ...
}

2

通过在包含WebView的活动中手动触发touchend事件来解决问题,像这样:ACTION_UP运动事件。

//onCreate method
webView.setOnTouchListener(new View.OnTouchListener() 
{
   @Override
   public boolean onTouch(View view, MotionEvent motionEvent) 
   {
      if(motionEvent.getAction() == MotionEvent.ACTION_UP) 
      {
         webView.loadUrl("javascript:document.dispatchEvent(new CustomEvent('touchend'))");
      }
      return false;
   }
});

1

“touchcancel” 会在用户开始滚动后立即触发,并且由于错误而无法正确触发“touchend”,因此无法知道用户何时释放了手指。希望我有时间检查你的android-swipe-shim,但恐怕它也无法检测到“指释放”,也就是“touchend”。 - Petr Peller

1
这里提供一种保持滚动启用的解决方案:
在touchMove处理程序中添加preventDefault(),但将其包装在一个条件语句中,以检查是否存在水平滚动运动。
onTouchStart = function (e) {                // Save start position
  startX = e.originalEvent.touches[0].pageX;
  startY = e.originalEvent.touches[0].pageY;
}

onTouchMove = function (e) {
  currentX = e.originalEvent.touches[0].pageX;
  currentY = e.originalEvent.touches[0].pageY;
  translateY = Math.abs(currentY - startY);
  if (translateY < 10) {   // If we are not (yet) scrolling vertically:
    e.preventDefault()
  }
}

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