2011-04-26 14 views
27

Tenemos un sitio web de juegos de cartas que hace un uso extensivo de jQuery Draggable & Droppable y que ha funcionado casi sin problemas (cuando se usa un mouse) durante casi un año.jQuery Arrastrar y soltar en dispositivos táctiles (iPad, Android)

REALMENTE nos gustaría que el sitio funcione en dispositivos de pantalla táctil, pero parece que no podemos conseguir que el arrastre de jQuery y especialmente la funcionalidad de soltar funcionen de manera confiable.

Arrastrar funciona "ok" a menos que el div arrastrado esté dentro de otro elemento dom con cualquier tipo de desplazamiento, margen, relleno, etc. Si lo está, el elemento arrastrado también se desplazará del dedo del usuario en una cantidad similar. Puede que no parezca un gran problema, pero hace que la interfaz no sea útil.

Dejar caer simplemente no parece funcionar.

Hemos investigado varias opciones presentadas aquí en SO (intentaremos actualizar esta publicación con enlaces a algunas de ellas si puedo), pero ninguna funciona para nosotros.

También hemos investigado jQuery Mobile, pero esto todavía está en alfa e incluso parece ser más un marco para que un sitio emule la interfaz de usuario de un teléfono frente a lo que estamos buscando.

La mayoría de las publicaciones de SO y Google sobre este tema parecen desaparecer a finales de 2010, lo que me hace pensar que hay una respuesta obvia que tal vez solo nos falta.

BTW, la funcionalidad que estamos buscando es claramente técnica porque las bibliotecas YUI para arrastrar y soltar funcionan como se esperaba. Desgraciadamente, no podemos justificar la refacturación del sitio para cambiar de jQuery a YUI.

¿Alguien por ahí tiene alguna idea? Nos conformaríamos con una respuesta que solo sea compatible con iPad, pero realmente no es necesario que reordenemos el sitio existente.

Gracias!

+0

posible duplicado de [¿Cómo puedo hacer una interfaz de usuario jQuery 'arrastrable() 'div arrastrable para pantalla táctil?] (http://stackoverflow.com/questions/3026915/how-can-i-make-a-jquery-ui-draggable-div-draggable-for-touchscreen) – ahsteele

+0

Esto es de hecho una de las publicaciones SO que investigamos, pero la solución eliminable a la que se hace referencia en la publicación no t trabajo para nosotros – Pat

+0

Otra publicación SO que vimos fue; http://stackoverflow.com/questions/4755505/how-to-recogized-touch-event-using-jquery-for-ipad-safari-browser-is-it-possible – Pat

Respuesta

0

Puede probar este complemento pero parece funcionar para iphone, ipod y ipad. No estoy seguro si resuelve tu problema. Puede ser una específica ...

http://code.google.com/p/jquery-ui-for-ipad-and-iphone/

pero Android todavía en busca de una solución.

Avísame si te puede ayudar. Saludos Ricardo Rodrigues

+1

Encontró que esto soluciona el problema de Android. Pero todavía es un problema en la versión anterior ... por ejemplo, 2.1 HTC Hero. Adivina que desacelerar –

34

Pegar esto al comienzo de su archivo .js:

(function ($) { 
    // Detect touch support 
    $.support.touch = 'ontouchend' in document; 
    // Ignore browsers without touch support 
    if (!$.support.touch) { 
    return; 
    } 
    var mouseProto = $.ui.mouse.prototype, 
     _mouseInit = mouseProto._mouseInit, 
     touchHandled; 

    function simulateMouseEvent (event, simulatedType) { //use this function to simulate mouse event 
    // Ignore multi-touch events 
     if (event.originalEvent.touches.length > 1) { 
     return; 
     } 
    event.preventDefault(); //use this to prevent scrolling during ui use 

    var touch = event.originalEvent.changedTouches[0], 
     simulatedEvent = document.createEvent('MouseEvents'); 
    // Initialize the simulated mouse event using the touch event's coordinates 
    simulatedEvent.initMouseEvent(
     simulatedType, // type 
     true,    // bubbles      
     true,    // cancelable     
     window,   // view      
     1,    // detail      
     touch.screenX, // screenX      
     touch.screenY, // screenY      
     touch.clientX, // clientX      
     touch.clientY, // clientY      
     false,   // ctrlKey      
     false,   // altKey      
     false,   // shiftKey     
     false,   // metaKey      
     0,    // button      
     null    // relatedTarget    
     ); 

    // Dispatch the simulated event to the target element 
    event.target.dispatchEvent(simulatedEvent); 
    } 
    mouseProto._touchStart = function (event) { 
    var self = this; 
    // Ignore the event if another widget is already being handled 
    if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) { 
     return; 
     } 
    // Set the flag to prevent other widgets from inheriting the touch event 
    touchHandled = true; 
    // Track movement to determine if interaction was a click 
    self._touchMoved = false; 
    // Simulate the mouseover event 
    simulateMouseEvent(event, 'mouseover'); 
    // Simulate the mousemove event 
    simulateMouseEvent(event, 'mousemove'); 
    // Simulate the mousedown event 
    simulateMouseEvent(event, 'mousedown'); 
    }; 

    mouseProto._touchMove = function (event) { 
    // Ignore event if not handled 
    if (!touchHandled) { 
     return; 
     } 
    // Interaction was not a click 
    this._touchMoved = true; 
    // Simulate the mousemove event 
    simulateMouseEvent(event, 'mousemove'); 
    }; 
    mouseProto._touchEnd = function (event) { 
    // Ignore event if not handled 
    if (!touchHandled) { 
     return; 
    } 
    // Simulate the mouseup event 
    simulateMouseEvent(event, 'mouseup'); 
    // Simulate the mouseout event 
    simulateMouseEvent(event, 'mouseout'); 
    // If the touch interaction did not move, it should trigger a click 
    if (!this._touchMoved) { 
     // Simulate the click event 
     simulateMouseEvent(event, 'click'); 
    } 
    // Unset the flag to allow other widgets to inherit the touch event 
    touchHandled = false; 
    }; 
    mouseProto._mouseInit = function() { 
    var self = this; 
    // Delegate the touch handlers to the widget's element 
    self.element 
     .on('touchstart', $.proxy(self, '_touchStart')) 
     .on('touchmove', $.proxy(self, '_touchMove')) 
     .on('touchend', $.proxy(self, '_touchEnd')); 

    // Call the original $.ui.mouse init method 
    _mouseInit.call(self); 
    }; 
})(jQuery); 

Llámame por la mañana;) (que es muy arrogante, que no he escrito esta solución, aunque me gustaría que tenía , me gustaría hacer referencia a ella si no recuerdo donde lo encontré, si alguien sabe donde este código vino de por favor comente y el crédito de esa persona)

ACTUALIZACIÓN: Aquí van: This is where I found this

+1

+1 que está enfermo, funciona bien en mi iPad –

+0

Woorks bien en la mayoría de las cosas, excepto BB w/trackball –

+1

Muy bien, pero ¿puedes decirme por qué esto destruye mi doble clic? jquery '.dblclick()' –

16

I sugerir jQuery UI Touch Punch. Lo probé en iOS 5 y Android 2.3 y funciona muy bien en ambos.

+0

pero tiene un poco de retraso/retraso antes de que comience el arrastre (probado en Chrome Andriod) – ProblemsOfSumit

+0

deslizador de rango de trabajo no funciona sin problemas en el dispositivo Android, por favor ayúdenme – ShibinRagh

4

Tema viejo Sé .......

Problema con la respuesta de @likwid_t es que bloquea también cualquier entrada u otro elemento que tiene que reaccionar en 'clics' (por ejemplo, entradas), así que escribí esta solución. Esta solución hizo posible usar cualquier biblioteca existente de arrastrar y soltar que esté basada en eventos de mousedown, mousemove y mouseup en cualquier dispositivo táctil (o cumputer). Esta es también una solución de navegador cruzado.

He probado en varios dispositivos y funciona rápido (en combinación con la función de arrastrar y soltar de ThreeDubMedia (consulte también http://threedubmedia.com/code/event/drag)). Es una solución de jQuery para que pueda usarla solo con jQuery libs. He usado jQuery 1.5.1 para ello porque algunas funciones más nuevas de no funcionan correctamente con IE9 y superior (no probado con las versiones más recientes de jQuery).

Antes agregar cualquier arrastra y coloca operación para un evento usted tiene que llamar a esta función primera:

simulateTouchEvents(<object>); 

También puede bloquear todos los componentes/hijos para la entrada o para acelerar gestión de eventos utilizando la siguiente sintaxis:

simulateTouchEvents(<object>, true); // ignore events on childs 

Aquí está el código que escribí. Utilicé algunos buenos trucos para acelerar la evaluación de las cosas (ver código).

function simulateTouchEvents(oo,bIgnoreChilds) 
{ 
if(!$(oo)[0]) 
    { return false; } 

if(!window.__touchTypes) 
{ 
    window.__touchTypes = {touchstart:'mousedown',touchmove:'mousemove',touchend:'mouseup'}; 
    window.__touchInputs = {INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,'input':1,'textarea':1,'select':1,'option':1}; 
} 

$(oo).bind('touchstart touchmove touchend', function(ev) 
{ 
    var bSame = (ev.target == this); 
    if(bIgnoreChilds && !bSame) 
    { return; } 

    var b = (!bSame && ev.target.__ajqmeclk), // Get if object is already tested or input type 
     e = ev.originalEvent; 
    if(b === true || !e.touches || e.touches.length > 1 || !window.__touchTypes[e.type] ) 
    { return; } //allow multi-touch gestures to work 

    var oEv = (!bSame && typeof b != 'boolean')?$(ev.target).data('events'):false, 
     b = (!bSame)?(ev.target.__ajqmeclk = oEv?(oEv['click'] || oEv['mousedown'] || oEv['mouseup'] || oEv['mousemove']):false):false; 

    if(b || window.__touchInputs[ev.target.tagName]) 
    { return; } //allow default clicks to work (and on inputs) 

    // https://developer.mozilla.org/en/DOM/event.initMouseEvent for API 
    var touch = e.changedTouches[0], newEvent = document.createEvent("MouseEvent"); 
    newEvent.initMouseEvent(window.__touchTypes[e.type], true, true, window, 1, 
      touch.screenX, touch.screenY, 
      touch.clientX, touch.clientY, false, 
      false, false, false, 0, null); 

    touch.target.dispatchEvent(newEvent); 
    e.preventDefault(); 
    ev.stopImmediatePropagation(); 
    ev.stopPropagation(); 
    ev.preventDefault(); 
}); 
return true; 
}; 

Lo que hace: En un primer momento, se traduce eventos táctiles individuales en eventos de ratón. Comprueba si un evento está causado por un elemento en/en el elemento que debe arrastrarse. Si se trata de un elemento de entrada como input, textarea, etc., omite la traducción, o si un evento de mouse estándar se adjunta también saltará una traducción.

Resultado: Cada elemento en un elemento arrastrable sigue funcionando.

codificación feliz, greetz, Erwin Haantjes

+0

Su el código fue de lo más útil. Lo he usado con FullCalendar pero no de fábrica. Lo hice para que el mouse se emule solo después de sostenerlo durante medio segundo. Ese fue el desplazamiento todavía funciona. Me gustaría que pusieras este código en Github para que yo pueda contribuir. Creo que podría usar algunas mejoras también ... que es "b" por ejemplo ... las variables están llorando por nombres detallados. :-) Pero bueno, ¡funciona! Muy apreciado. – RushPL

+0

Consulte mi respuesta a continuación: http://stackoverflow.com/a/13649533/403571 – RushPL

+0

Los nombres detallados son importantes, lo sé, pero uso en este código 'b' un booleano multiuso (b de booleano) para verificar algunas condiciones para que sea mejor legible y para limitar temporalmente los vars. Pero gracias de todos modos por tu contribución. – Codebeat

0

LikWidT tiene las manos hacia abajo solución más sencilla desde el sitio web de referencia. Sería genial si cualquiera de los programadores de IU de JQuery pudiera agregar este código o similar a su paquete. Jquery es sin duda el paquete más simple para crear contenido de arrastrar/soltar para desarrolladores web ... Desafortunadamente, este es un error importante con casi todos los dispositivos que tienen pantallas táctiles hoy en día. Ahora estoy programando un Surface Pro que me está abriendo los ojos personalmente a estos problemas.

Simplemente hacer referencia a la página web de nuevo: https://github.com/furf/jquery-ui-touch-punch

Editar: También para aclarar lo simple que es fijo. Primero tuve que asegurarme de haber reordenado mis archivos de inclusión de modo que el archivo JQuery Javascript fuera primero, luego Jquery UI Javascript y luego mis archivos CSS. Luego copié/pegué debajo de los archivos de inclusión el código Javascript en la publicación de arriba y eso fue todo. Modifiqué ningún código, es simplemente una función que busca cualquier toque en tiempo real y los convierte en acciones de mouse equivalentes. De ahí mis afirmaciones anteriores para los codificadores de JQuery.

0

Dada trabajó para mí:

eventAfterRender: function (event, element, view) { 
     element.draggable(); 
}, 
0

Probado en HTC One M8 bajo Android 6.13/tableta Samsung Galaxy S2

function simulateMouseEvent (event, simulatedType) { //use this function to simulate mouse event 

// restriction to preserve input use 
    window.__touchInputs = {INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,'input':1,'textarea':1,'select':1,'option':1}; 
    if(window.__touchInputs[event.target.tagName]) return ; 

} 
Cuestiones relacionadas