Webkit iphone / ipad проблема с Mutl-Touch - PullRequest
       15

Webkit iphone / ipad проблема с Mutl-Touch

6 голосов
/ 12 сентября 2010

В UIWebView (с поддержкой мультитач) я получил страницу с двумя элементами div (div1 и div2), каждый из которых зарегистрировался для событий touchstart и touchend.Каждый раз, когда они получают сенсорные события, я выгружаю содержимое:

  • event.touches: содержит все текущие касания
  • event.targetTouches: содержит касания, относящиеся к данной цели
  • event.changedTouches: содержит касания, вызвавшие событие

Рассмотрим следующий сценарий:

  • нажатие на div1: event.touches содержит div1
  • , не отпуская div1, нажмите на div2: event.touches содержит div1 и div2
  • отпустите div2, но не div1: event.touches пуст, это не должно произойти, так как div1 все еще нажимается.Также div1 получил событие касания, как если бы оно было выпущено
  • , подождите некоторое время, все еще нажав div1, и он получит новое событие запуска прикосновения, которое не имеет смысла, так как оно никогда не было выпущено.

Таким образом, при отпускании одного пальца он действует так, как если бы оба пальца были удалены.Я что-то пропустил?

Ответы [ 4 ]

1 голос
/ 13 сентября 2010

Спасибо funkybro за ваш комментарий, но, к сожалению, я могу наблюдать такое же ошибочное поведение при перехвате событий касания на уровне документа. Вот след того, что происходит:

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: Вот пример кода для запуска в Safari Mobile или внутри собственного UIWebView на устройстве (не на симуляторе).

<!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 голосов
/ 02 января 2011

Похоже, эта проблема была исправлена ​​в iOS 4.2 (Я не смог воспроизвести его на iPhone 4 с iOS 4.2.1)

0 голосов
/ 17 ноября 2010

У меня есть решение, но оно не оптимально. Следите за touch.identifier при возникновении событий touchstart. Когда вы получаете событие касания, setinterval 500 мс. Если в течение интервала сработал другой каскад и сенсорный запуск, посмотрите, есть ли у сенсорного старта существующий идентификатор касания, и вы можете определить, какой палец был поднят.

Когда два пальца опущены, во время первого касания невозможно определить, какой палец поднялся. Я посмотрел на порядок изменений TouchTouch, я проверил сохраненную копию событий touchstart. Я посмотрел на события жестов, которые предшествуют сбою. Задержка повторного касания оставшегося пальца зависит от срабатывания касания.

Если эта ошибка нарушает ваше взаимодействие с несколькими касаниями, добавьте отзыв к этому явно неправильному описанию последовательности событий в документации для разработчиков. Справочник по классам GestureEvent

0 голосов
/ 13 сентября 2010

Да, я тоже нашел это.Похоже, это должно быть ошибкой, но я не уверен.

Самый гибкий способ, который я нашел, чтобы сделать все виды мультитач-совершенства в iOs webkit, - это захват сенсорных событий на весь документ , т. е. звоните document.addEventListener() для всех интересующих вас событий касания.

Затем используйте некоторую тактику, чтобы выяснить, с каким элементом произошло касание.Вы можете:

  • Изучить свойство сенсора target, чтобы получить некоторую информацию об элементе.Однако (еще одна возможная ошибка?), Вы не можете узнать идентификатор элемента из этого свойства, только его класс, который не подходит для различения нескольких элементов, использующих один и тот же класс.Изучите источник этой виртуальной таблицы освещения JS для iOs , чтобы увидеть это в действии.

  • Сравните координаты касания pageX и pageY,с размерами и позициями каждого из элементов, к которым может относиться касание (относительно документа).Например, используя 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!
    }
    

При использовании этого метода все сенсорные действия ведут себя совершенно так, как вы ожидаете:)

...