touchend event doesn't work on Android

2019-01-16 13:14发布

问题:

I've just started looking at doing some basic mobile web development on the android and an writing a test script to investigate the touch events. I've run the following code in the android emulator, and the touchend event never gets fired. Can anyone tell me why ?

I've tried in three versions of the emulator (1.6, 2.1 and 2.2) and all three behave in the same way.

Thanks in advance for any help you can give me.

Cheers, Colm

EDIT - I've also tried this using the XUI framework and have the same problem so I'm guessing I have a fundamental misunderstanding of how this stuff works ......

Map Test

    <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:

For anyone trying to figure out why touchend events are missing on Android v3 and v4 (maybe also v2.3), there is a long outstanding bug which only just got fixed in v4.1 (apparently):

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

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

To workaround this bug you have to call preventDefault() on either the touchstart or first touchmove event. Of course, this prevents the native scrolling, so you will need to re-implement that yourself.



回答2:

This is how you need to use it properly. You capture the starting x,y when the finger goes to the screen. As the finger moves across, the touchmove event updates an ending x,y. When finished, the touchend fires -- but yes, it doesn't have a touches array, and thus a javascript error. This is why we only use it for capturing that this is an ending task (fingers left the screen) and then react to it. (In this case, I send an informative alert.)

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);


回答3:

It's web development, so I am building a webpage that can utilize the touch events.

I figured out what the problem was.

When the touchend event is fired the event.touches[] array is empty, so a Javascript error is thrown. The event was being fired, but it didn't print anything out, because I was attempting to access undefined data. The emulator browser doesn't seem to have any Javascript debugging tools that I have found, and didn't even tell me when a Javascript error occurred, so it took me a while to figure it out.



回答4:

The TouchList is always empty when touchend event is fired because you removed all fingers from the screen :).

http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/



回答5:

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


回答6:

I had the same problem and additionally binding the 'touchcancel' event solved it. Did some testing and when 'touchend' wasn't fired, then the 'touchcancel' event fired instead.

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


回答7:

This occurs on KitKat and is solved by handling touchcancel according to android dev http://developer.android.com/guide/webapps/migrating.html#TouchCancel

For older android versions the problem is caused by android no passing touch events to webview if preventdefault is not applied to the touchstart event. This is hard-coded into millions of android devices. https://github.com/TNT-RoX/android-swipe-shim



回答8:

I was able to fix the problem by triggering the touchend event manually on ACTION_UP motion event from the activity that contains the WebView like this:

//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;
   }
});


回答9:

Here a solution to keep scrolling enabled:

Add a preventDefault() in the touchMove handler, but wrap it in a conditional that checks for lateral scroll movement:

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