Множественные касания: событие touchhend срабатывает только тогда, когда возникает сенсорная манипуляция

Я хотел бы добавить некоторые мультитач-функции в мое приложение javascript, когда он будет доступен с устройства ios (и, возможно, андроида позже).

Я хочу предоставить функциональность, подобную shiftkey: пользователь может удерживать кнопку на экране одним пальцем, и пока эта кнопка нажата, поведение для действия крана на остальной части экрана немного отличается от классический кран.

Проблема, с которой я сталкиваюсь, заключается в том, что я не получаю событие touchhend для касания пальца, если не будет нажата touchmove для первого пальца, удерживающего кнопку shiftkey.

Поскольку экран очень чувствительный, события touchmove легко запускаются, и в большинстве случаев все работает нормально.

Но когда пользовательский палец немного слишком неподвижен, постукивание не обнаружено, пока пользователь не слегка пошевельнет пальцем. Это вызывает переменную "задержку" между нажатием и действием, которое происходит на экране (задержка может варьироваться и длиться несколько секунд, если пользователь очень спокоен). Я предполагаю, что эта задержка заставит пользователя снова нажать и, таким образом, запустить действие во второй раз, чего я не хочу!

Вы можете протестировать его здесь с помощью ipad/iphone: http://jsfiddle.net/jdeXH/8/

Попытайтесь заставить тело оставаться зеленым в течение нескольких секунд, держа палец очень неподвижно на голубом div, постукивая по красному div.

Ожидается ли такое поведение? Существует ли какое-то известное решение проблемы? Я бы ожидал, что событие touchhend будет запущено сразу же после удаления пальца с экрана.

i тестировал это с помощью iOS 5.1.1 (ipad1 и iphone4s)

edit: нашел аналогичный вопрос Мультитач touchEvents не запускался, как следует на Safari Mobile

Ответ 1

Ну, похоже, что ошибка беспокоила несколько человек больше меня, они подали ошибку прямо на яблоко, и через несколько лет она теперь фиксируется в iOS6:)

Ответ 2

Хорошо, это головная боль. Да, есть две известные проблемы. Прежде всего, Safari иногда не беспокоится об увольнении события touchEnd, если там нет touchMove, даже если touchMove на самом деле мало что делает.

second, Chrome Mobile - прекрасный опыт, так как на многих устройствах Android событие touchEnd не срабатывает вообще, независимо от того, что вы делаете. Поэтому по моему опыту:

  • Внедрить событие touchStart, которое регистрирует начальную координату и т.д.
  • Импланировать событие touchMove, которое делает то же самое, что и touchEnd, но убедитесь, что обратный вызов не срабатывает более одного раза. Используйте флаг boolean, определенный в более высокой области видимости или что-то в этом роде.
  • Внедрение обычного события touchEnd, которое должно срабатывать только в том случае, если touchMove еще не активировал обратный вызов, используя тот же логический флаг, определенный в более высокой области.

Ответ 3

Хорошо, я реализовал это решение и, похоже, работает.

//Initialize the tap touch
function ManageTapTouch() {
    this.__enabled__ = false;
}

ManageTapTouch.prototype.init = function(){
    $("#hold").bind('touchstart', $.proxy(this.__enable__, this));
    $('#hold').bind('touchend', $.proxy(this.__disable__, this));
    $('#tap').bind('touchstart',  $.proxy(this.__changeColorOnHold__, this));
    $('#tap').bind('touchend',  $.proxy(this.__changeColorOnOut__, this));
};
ManageTapTouch.prototype.__enable__ = function(event) {
    this.__enabled__ = true;
};
ManageTapTouch.prototype.__disable__ = function(event) {
    this.__enabled__ = false;
    $('body').css('background-color', 'blue'); 
};
ManageTapTouch.prototype.__changeColorOnHold__ = function(event) {
    if (this.__enabled__){
        $('body').css('background-color', 'black');
    }
};
ManageTapTouch.prototype.__changeColorOnOut__ = function(event) {
    $('body').css('background-color', 'blue');
};

new ManageTapTouch().init();

Вы можете увидеть, как он работает здесь: http://jsfiddle.net/Tb6t6/15/

Также вы можете попробовать другой способ на iPhone с помощью multitouch с: event.originalEvent.touches[0].pageX и event.originalEvent.touches[0].pageY, где указатель является пальцем на экране, а событие - событием, запущенным на TouchStart. С помощью этих тем вы можете реализовать свою собственную версию этого действия или использовать ту, которую я предлагаю здесь.

Ответ 4

Итак, похоже, вы достигли одного из тех сценариев, которых нельзя избежать, и будут иметь только багги-хаки. Вы создаете функцию пользовательского интерфейса, которая пока не совсем "норма", но, похоже, имеет некоторые перспективы (мне нравится... мне нравится). Вопрос, который нужно задать себе в этой точке техники, - "как я могу заставить пользователя скользить пальцем, чтобы удерживать сдвиг".

С помощью хорошего дизайнера я думаю, что вы можете создать скользящую кнопку переключения, похожую на флип-переключатель... где пользователь должен перетащите и удерживайте, чтобы включить переключатель "on". После отпускания переключатель spring вернется в положение "off". Я упоминаю дизайнера, потому что кнопка должна выглядеть так, как будто она ведет себя. Возможно, некоторые из комментариев могут стать творческими.