2010-09-12 6 views
6

In una UIWebView (multi-touch abilitato) Ho ottenuto una pagina con due div (div1 e div2), ognuno dei quali si è registrato per gli eventi touchstart e touchend. Ogni volta che stanno ricevendo gli eventi touch, sto Dumping il contenuto di:Problema di iphone/ipad Webkit con mutl-touch

  • event.touches: contiene tutti gli attuali tocchi
  • event.targetTouches: contiene tocchi rilevanti per il determinato obiettivo
  • evento. changedTouches: contiene tocchi aver attivato l'evento

Si consideri il seguente scenario:

  • rubinetto div1: event.touches contiene div1
  • senza rilasciare div1, toccare il div2: event.touches contiene div1 e div2
  • liberatoria div2 ma non div1: event.touches è vuoto, dovrebbe non come div1 è ancora premuto. Anche div1 ha ricevuto un evento touchend come se fosse stato rilasciato
  • aspetta un po ', mantenendo premuto il tasto div1, e riceverà un nuovo evento touchstart, che non ha senso in quanto non è mai stato rilasciato.

Quindi in pratica quando si rilascia un dito, si comporta come se fossero state rimosse entrambe le dita. Mi sto perdendo qualcosa?

+0

appena imbattuto lo stesso problema, su un iPod. Uso JavaScript, quindi il problema sembra essere piuttosto elementare (bug o incomprensione dalla nostra parte ;-). – mar10

+0

sì, io sono sorpreso di incontrare un problema del genere in quanto questo è piuttosto grande, il multi-touch è quasi inutilizzabile in questo contesto. Spero ci manchi qualcosa ... – Alio

+0

Penso di aver colpito lo stesso problema? http://stackoverflow.com/questions/3666929/mobile-sarai-touchend-event-not-firing-when-last-touch-is-removed puoi confermare? –

risposta

0

Sì, ho trovato anche questo. Sembra che dovrebbe essere un bug, ma non ne sono sicuro.

Il modo più flessibile che ho trovato per fare ogni sorta di multi-touch bontà in iOS WebKit é per acquisire gli eventi di tocco sul intero documento, vale a dire chiamare document.addEventListener() per tutte le varietà di tocco evento che ti interessa.

Quindi utilizzare una certa tattica per capire su quale elemento il tocco è successo. È possibile:

  • Esaminare la proprietà del tocco target per avere alcune informazioni circa l'elemento. Tuttavia (un altro possibile errore?), Non è possibile trovare l'ID dell'elemento da questa proprietà, ma solo la sua classe, che non è utile per distinguere tra più elementi che utilizzano la stessa classe. Esaminare la fonte di this JS virtual light table for iOs per vedere ciò in azione.

  • Compare pageX e pageY coordinate del tocco, le dimensioni e le posizioni di ciascuno degli elementi touch potrebbe riguardare (relativi al documento). Ad esempio, utilizzando 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! 
    } 
    

Utilizzando questo metodo, tutte le azioni di contatto si comportano del tutto come ci si aspetterebbe :)

+0

Se ho capito bene, questo non aiuta nel mio caso: voglio tenere traccia di due tocchi indipendenti su un singolo elemento. – mar10

+0

Questo ti aiuterà in questo; puoi tenere traccia di tutti i tocchi che vuoi sull'intera pagina, su tutti gli elementi che desideri. – funkybro

+0

sì, ma come accennato nell'altra risposta, non appena si alza un dito, non si saprà quale dito è stato rilasciato come tutti i tuoi elementi riceveranno un tocco anche con tocchi vuoti. Se questo non è importante per l'utilizzo che vuoi fare del multi-touch, allora va bene, se è importante, allora dimentica il webkit fintanto che questo bug è presente. Sembra che tu voglia tenere traccia dei tocchi sullo stesso elemento così dovresti stare bene. – Alio

1

Grazie funkybro per il tuo commento, ma purtroppo posso stil osservare lo stesso erroneo comportamento quando si intercettano gli eventi tattili a livello di documento.Ecco una traccia di ciò che sta accadendo:

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) 

Edit: Ecco un esempio di codice, per funzionare su Safari Mobile o all'interno del proprio UIWebView sul dispositivo (non simulatore).

<!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> 
+0

Questo dovrebbe idealmente essere un'aggiunta alla risposta originale o una risposta al mio commento, non una risposta in sé. – funkybro

+0

right, sorry per questo ... – Alio

+0

Non capisco il tuo debug, ma sembra che tu abbia ancora ascoltatori collegati a ogni singolo elemento, questo è ciò che sta causando il comportamento che osservi. Puoi incollare brevi frammenti rilevanti di codice reale nella tua domanda? – funkybro

0

Ho una soluzione, ma non è ottimale. Tieni traccia di touch.identifier come fuoco di eventi touchstart. Quando ottieni un evento di tocco, imposta un intervallo di 500 ms. Se durante l'intervallo sono stati attivati ​​un altro tocco e un touchstart, verificare se il touchstart ha un identificatore touch esistente e determinare il dito sollevato.

Quando due dita sono abbassate non è possibile determinare al momento del primo tocco che il dito si è sollevato. Ho esaminato l'ordine dei Touches modificati, ho controllato una copia salvata degli eventi touchstart. Ho guardato gli eventi del gesto che precedono il problema tecnico. Il ritardo nell'avvio duplicato del dito rimanente dipende dall'attivazione del touchmove.

Se questo bug interrompe l'interazione multi-touch, aggiungi feedback a questa descrizione chiaramente errata della sequenza di eventi nei documenti dello sviluppatore. GestureEvent Class Reference

0

Sembra che questo problema è stato risolto in iOS 4.2 (non ho potuto riprodurla su un iPhone 4 con iOS 4.2.1)

+0

iOS 4.2 ha migliorato le cose ma questo non è completamente risolto. A seconda dei tempi e del numero di elementi da premere, può apparire il ritardo. – Alio