Как отключить iOS Shake для отмены в веб-приложении

Я создаю игру как веб-приложение для iPad. Он включает в себя действие встряхивания, чтобы вызвать событие для одного из экранов, но, поскольку он также имеет форму сбора информации, иногда это действие встряхивания запускает раздражающий диалог «Встряхнуть, чтобы отменить». Форма ввода, которую ввел пользователь, больше даже не существует в DOM, когда пользователь достигает действия встряхивания, поэтому, на мой взгляд, функция отмены не должна запускаться, но, к сожалению, это так. Невозможно обернуть это в собственную оболочку (PhoneGap или другую), поэтому мне было интересно, знает ли кто-нибудь, можно ли вообще отключить эту функцию для определенной веб-страницы / приложения через CSS или JavaScript?

Спасибо.


person Johan Sahlén    schedule 29.06.2011    source источник


Ответы (9)


Недавно я столкнулся с этой проблемой при разработке игры, в которой пользователь соединяет устройства с помощью WebSockets. К сожалению, ни одно из упомянутых выше решений не работает.

Короче говоря, в игре участвовал пользователь, подписывающийся на канал через форму на своем телефоне. После подписки они встряхивали устройство, и сценарий воспроизводился на их рабочем столе. Проблема заключалась в том, что всякий раз, когда кто-то встряхивал устройство iOS, всплывало предупреждение «Отменить ввод».

Вот единственные два решения, которые я нашел для этой проблемы.

  1. Не допускайте потери внимания при вводе. Это потребует от вас запретить отправку формы, если ввод является частью формы. Вы также должны прослушивать «touchstart» вместо «click» на любых привязках и предотвращать распространение события touchstart. Это предотвратит фокусировку этого якоря и потерю вашего ввода. У такого подхода наверняка есть недостатки.

  2. Добавьте в окно обработчик события keydown и предотвратите распространение события. Это предотвращает вставку каких-либо значений во вход на устройствах iOS. Мне также пришлось создать объект, который сопоставил бы коды клавиш с нужным персонажем. Это тот путь, которым я закончил, потому что все, что мне нужно было во вводе, было 6-символьным кодом, поэтому мне были нужны только числа. Если вам нужно больше, чем просто цифры, это может быть головной болью. Нажав клавишу, зацепите этот символ с помощью кода клавиши и установите значение ввода. Это заставляет iOS думать, что никакое значение никогда не было вставлено во ввод с клавиатуры, поэтому отменять его нечего.

Имейте в виду, что предотвращение распространения события keydown не предотвращает ввод в стандартном браузере Android, поэтому он просто будет нормально работать. Но это нормально, поскольку это не проблема Android. Вы можете предотвратить вставку повторяющихся значений, прослушивая событие ввода на самом вводе и удаляя прослушиватель нажатия клавиш, если это событие получено.

var codes = {
  48: 0,
  49: 1,
  50: 2,
  51: 3,
  52: 4,
  53: 5,
  54: 6,
  55: 7,
  56: 8,
  57: 9
},
myInput = document.getElementById("myInput");

var keydownHelper = function (e) {
  e.preventDefault();
  myInput.removeEventListener("input", inputHelper); 

  var val = myInput.value;

  // Delete
  if (e.keyCode === 8 && val.length) {
    myInput.value = val.slice(0, val.length - 1);
    return;
  }

  // If not a number, do nada
  if (typeof codes[e.keyCode] === "undefined") { return; }

  val += codes[e.keyCode];
  myInput.value = val;
};

var inputHelper = function (e) {
  e.preventDefault();
  window.removeEventListener("keydown", keydownHelper);
};

myInput.addEventListener("input", inputHelper);
window.addEventListener("keydown", keydownHelper); 
person Maxsquatch    schedule 24.04.2013
comment
Спасибо, что поделился! Я не в состоянии создать тестовый пример прямо сейчас, но ваш ответ, кажется, очень хорошо исследован и соответствует тому, что я просил в исходном вопросе, поэтому я принимаю его как правильный, если никто не любые возражения :) - person Johan Sahlén; 25.04.2013

Для PhoneGap я просто вставил эту строку: [UIApplication sharedApplication] .applicationSupportsShakeToEdit = NO; в классе webViewDidFinishLoad, и это творило для меня чудеса.

Просто перейдите в MainViewController.m и измените webViewDidFinishLoad, чтобы он выглядел так:

- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
    // Black base color for background matches the native apps
    theWebView.backgroundColor = [UIColor blackColor];

[UIApplication sharedApplication].applicationSupportsShakeToEdit = NO;

    return [super webViewDidFinishLoad:theWebView];
}
person Tobias Christian Jensen    schedule 09.05.2013

В этом блоге описывается очень простое обнаружение дрожания с помощью прослушивателя DeviceMotionEvent:

http://www.jeffreyharrell.com/blog/2010/11/creating-a-shake-event-in-mobile-safari/.

Попробуйте следующий код, чтобы отключить, чтобы отменить событие:

window.addEventListener('devicemotion', function (e) {
    // This is where you put your code for dealing with the shake event here

    // Stop the default behavior from triggering the undo dialog (hopefully)
    e.preventDefault();
});

Есть еще одна вещь, которую я могу придумать, - это превратить вводимый текст в элемент только для чтения после того, как вы закончите с ним. Предположительно, поле ввода только для чтения не может использовать функцию отмены, хотя я ее не тестировал. Странно, что функция срабатывает даже после того, как ввод больше не является частью DOM.

Я не уверен, можно ли предотвратить действие встряхивания с помощью свойств -webkit- в CSS. Вот список свойств CSS, специфичных для webkit (который может не содержать 100% доступных свойств).

http://qooxdoo.org/documentation/general/webkit_css_styles

person John Kramlich    schedule 29.06.2011
comment
Хорошая идея, но, к сожалению, не повезло. Даже при присоединении (или использовании функции делегата Zepto) событие к самим элементам ввода диалоговое окно «Отменить» все равно появляется. - person Johan Sahlén; 01.07.2011
comment
Да, и установка ввода только для чтения, к сожалению, по-прежнему вызывает всплывающее диалоговое окно. - person Johan Sahlén; 01.07.2011
comment
Это не работает с текущей версией Cordova (7.0.1). Ответ Тобиаса Кристиана Дженсенса работает отлично. Просто добавьте [UIApplication sharedApplication].applicationSupportsShakeToEdit = NO; в didFinishLaunchingWithOptions функцию Classes/AppDelegate.m - person David Schumann; 28.09.2017

Цель-C

Просто добавьте строку кода внутри «- (BOOL) application: (UIApplication *) application didFinishLaunchingWithOptions: (NSDictionary *) launchOptions»

[application setApplicationSupportsShakeToEdit:NO];

Swift 2.x

Добавьте одну строку кода в метод appDelegate.swift didFinishLaunchingWithOptions

func application (application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    application.applicationSupportsShakeToEdit = false
    return true
}

Swift 3.x

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    application.applicationSupportsShakeToEdit = false
    return true
}
person Augustine P A    schedule 05.08.2014

Может быть, попробовать event.preventDefault(); в слушателе DeviceMotionEvent?

Оглядываясь на Stack Overflow, я вижу, что другим людям удалось отключить стандартные «события» с помощью CSS (как ни странно).

Запретить нажатие по умолчанию, но не перетаскивание по умолчанию iOS MobileSafari?

person Alex KeySmith    schedule 29.06.2011

См .: Как остановить UITextField от ответа на жест встряхивания?

Для телефонного разговора установите это свойство в методе webViewFinishLoad в AppDelegate.m

person Bob Dowling    schedule 05.10.2012

Первое решение

Самый простой способ - использовать этот плагин:

https://github.com/nleclerc/cordova-plugin-ios-disableshaketoedit

Второе решение

Если вы не хотите использовать указанный выше плагин, вам следует сделать это вручную, открыв MainViewController.m и изменив webViewDidFinishLoad, чтобы он выглядел следующим образом:

- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
    // Black base color for background matches the native apps
    theWebView.backgroundColor = [UIColor blackColor];

[UIApplication sharedApplication].applicationSupportsShakeToEdit = NO;

    return [super webViewDidFinishLoad:theWebView];
}

Третье решение

это еще одно решение, которое я разработал для отключения «Shake To Undo», который работает с вводом текста. обратите внимание, что пользователям не разрешается вставлять смайлы.

<body>
    <textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>

    <script>
    textArea = document.getElementById("textarea");

    textArea.onkeypress =  function(event){
        event.preventDefault();
        var nationUnicode=event.which;
        var utf8=encodeURIComponent(String.fromCharCode(parseInt(nationUnicode, 10)));
        if  (utf8.search("%EF") != 0) //value is not an Emoji
            textArea.value= textArea.value + String.fromCharCode(nationUnicode);
    }

    textArea.onkeydown = function (event){
        if (event.keyCode == 8){
            event.preventDefault();
            var txtval = textArea.value;
            textArea.value = txtval.slice(0, - 1);
        }   
    }
    </script>
</body>
person Saeed HosseinPoor    schedule 18.04.2017
comment
Большое спасибо за решение 3! Именно то, что я искал! Некоторые смайлы работают (например, мигают) - person vinni; 12.10.2017

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

function resetIframe() {
  // Remove the old frame
  document.body.removeChild(frame);

  // Create a new frame that has an input internally
  frame = document.createElement('iframe');
  frame.src = '/html-with-input.html';
  frame.style = 'border: 0; height: 30px; width: 200px;'
  document.body.appendChild(frame);

  // When the frame is ready, grab a reference to the input
  frame.addEventListener('load', () => {  
    const input = frame.contentDocument.body.querySelector('input');
    console.log(frame, frame.contentDocument.body)

    // When the input changes, grab the value
    input.addEventListener('input', e => {
      document.getElementById('output').innerText = e.target.value;
    });
  });
}

Вот подтверждение концепции: https://codepen.io/joshduck/full/RJMYRd/

person Josh Duck    schedule 21.06.2018

Поместите ввод в iframe, перезагрузите iframe, когда он вам не нужен.

person Ning    schedule 15.03.2016