2010-06-07 102 views
32

我刚开始考虑在android上做一些基本的移动web开发,并编写测试脚本来调查触摸事件。我在android模拟器中运行了以下代码,并且touchend事件永远不会被触发。谁能告诉我为什么?touchend事件不适用于Android

我已经尝试过三个版本的模拟器(1.6,2.1和2.2),并且所有三个版本的行为都是一样的。

在此先感谢您提供的任何帮助。

干杯, 科尔姆

编辑 - 我也试过这种使用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应用程序(例如,使用各种“视图”的“活动”),还是正在使用Android浏览器访问网页?如果您正在编写实际的Android应用程序,请注意'WebView'不适用于'onTouchEvent'回调。其内置的系统可以在大于屏幕的页面上与“MotionEvent”发生冲突,这样就会出现不一致的行为。 – 2010-06-07 10:35:40

+0

我在7in安卓平板电脑上也收到了这个问题,'touchend'事件永远不会触发..请参阅http://code.google.com/p/android/issues/detail?id=19827#makechanges – 2012-08-20 15:45:12

回答

6

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

我想出了问题所在。

touchend事件被触发时,event.touches[]数组为空,所以引发了Javascript错误。这个事件被解雇了,但它没有打印任何东西,因为我试图访问未定义的数据。模拟器浏览器似乎没有任何我找到的Javascript调试工具,甚至在发生Javascript错误时甚至没有告诉我,所以花了我一段时间才弄清楚。

19

这就是你需要如何正确使用它。当手指进入屏幕时,捕捉起始点x,y。随着手指移动,touchmove事件更新结尾x,y。完成后,触发器会触发 - 但是,它没有触摸数组,因此出现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); 
2
map.addEventListener ('touchend', function (event) { 
    var touch = event.changeTouches[0]; 
    ... 
} 
+0

这个解决方案对我来说很有用,谢谢 – 2016-01-26 15:07:41

31

对于任何人试图弄清楚为什么touchend事件失踪的Android V3和V4(也许还V2.3),还有很长的仅刚刚固定在V4.1(显然)优秀的错误:

http://code.google.com/p/android/issues/detail?id=4549

http://code.google.com/p/android/issues/detail?id=19827

要解决这个bug你必须调用preventDefault()在touchstart或first touchmove事件上。当然,这会阻止本地滚动,因此您需要自己重新实现。

+13

这个bug在Android 4.3上也不是固定的。 – BairDev 2013-12-23 12:52:28

+4

在4.4.2中有同样的问题。 – Rhyono 2014-03-27 00:54:51

+0

“当然,这可以防止本地滚动,所以您需要自己重新实现。” < - 我该怎么做? 首先,我有想法使用“e.preventDefault()”touchmove事件(使浏览器触发touchmove和touchend),而不是手动触发touchmove事件,但似乎没有办法实现滚动/ zooming ourselfes ... – lx222 2014-04-09 10:23:07

1

这发生在奇巧,并通过根据Android开发http://developer.android.com/guide/webapps/migrating.html#TouchCancel

对于较旧的Android版本的问题是由机器人没有通过触摸事件引起的,如果是的preventDefault不应用于touchstart事件的WebView处理touchcancel解决。这是硬编码到数以百万计的Android设备。 https://github.com/TNT-RoX/android-swipe-shim

+0

'touchcancel'在用户开始滚动后立即触发,并且无法知道用户何时释放他的手指,因为“touchend”由于错误而未正确启动。希望我会有一些时间来检查你的android-swipe-shim,但是恐怕它不能检测到“手指释放”又名'touchend'。 – 2015-02-01 03:42:30

1

我是能够通过从包含这样的web视图活性手动触发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; 
    } 
}); 
+0

这是大胆的,但它的作品:)你救了我的一天,谢谢。 – 2015-11-25 09:15:26

2

我有同样的问题,并且另外结合“touchcancel '事件解决了它。做了一些测试,当'touchend'没有被解雇,那么'touchcancel'事件就被解雇了。

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

我可以确认这对于android 5来说,找到了相同的解决方案。 – wessel 2016-10-19 12:25:07

0

这里的解决方案,以保持滚动启用:

中的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() 
    } 
}