如何在webapp中禁用iOS“Shake to Undo”

时间:2011-06-29 11:46:05

标签: javascript ios ipad html5 iphone-web-app

我正在构建一款适用于iPad的webapp游戏。它结合了一个摇动动作来触发其中一个屏幕的事件,但是,由于它还有一个信息收集表单,有时摇动动作会触发恼人的“摇动撤消”对话框。当用户到达摇动动作时,用户输入的表单输入甚至不再存在于DOM中,所以在我看来不应该触发撤销功能,但不幸的是它是。没有办法将它包装在本机包装器(PhoneGap或其他)中,所以我想知道是否有人知道是否可以通过CSS或JavaScript禁用特定网页/应用程序的此功能?

感谢。

9 个答案:

答案 0 :(得分:9)

此博客描述了使用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的一部分,该功能也会触发。

我不确定是否可以通过CSS中的-webkit-属性来防止抖动操作。以下是webkit特定CSS属性的列表(可能不包含100%可访问的属性)。

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

答案 1 :(得分:8)

对于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];
}

答案 2 :(得分:4)

我最近遇到了这个问题,同时开发了一个用户使用WebSockets配对设备的游戏。不幸的是,上面提到的解决方案都没有起作用。

简而言之,游戏涉及用户通过手机上的表单订阅频道。一旦订阅,他们就会动摇设备并在他们的桌面上播放一个场景。问题是每当有人震动iOS设备时,都会弹出“撤消打字”警报。

以下是我为此问题找到的唯一两种解决方案。

  1. 防止输入失去焦点。如果输入是表单的一部分,这将要求您阻止表单提交。您还必须在任何锚点上侦听“touchstart”而不是“click”,并防止touchstart事件传播。这样可以防止锚点获得焦点,输入也不会失去焦点。这种方法肯定有一些缺点。

  2. 向窗口添加“keydown”事件处理程序并阻止事件传播。这可以防止任何值插入到iOS设备上的输入中。我还必须创建一个将键码映射到正确字符的对象。这是我结束的路线,因为我输入的所有内容都是6个字符的代码所以我只需要数字。如果你需要的不仅仅是数字,这可能是一个痛苦的屁股。在按键时,通过键码捕获该字符并设置输入值。这让iOS认为没有任何值通过键盘输入到输入中,所以没有任何东西可以撤消。

  3. 请记住,防止keydown事件传播不会阻止在股票android浏览器上输入,因此它只会正常运行。但这没关系,因为这不是一个Android问题。您可以通过侦听输入本身的输入事件来防止插入重复值,并在收到此事件时删除keydown侦听器。

    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); 
    

答案 3 :(得分:4)

<强>目标C

只需在&#34; - (BOOL)应用程序中添加代码行:(UIApplication *)应用程序didFinishLaunchingWithOptions:(NSDictionary *)launchOptions&#34;

[application setApplicationSupportsShakeToEdit:NO];

Swift 2.x

在appDelegate.swift didFinishLaunchingWithOptions 方法中添加单行代码

  

func application(application:UIApplication,didFinishLaunchingWithOptions launchOptions:[NSObject:AnyObject]?) - &gt;布尔{

    application.applicationSupportsShakeToEdit = false
    return true
}

Swift 3.x

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

    application.applicationSupportsShakeToEdit = false
    return true
}

答案 4 :(得分:1)

也许在DeviceMotionEvent监听器中尝试event.preventDefault();

环顾Stack Overflow,我可以看到其他人已成功使用CSS禁用默认“事件”(奇怪)。

Prevent default Press but not default Drag in iOS MobileSafari?

答案 5 :(得分:1)

请参阅:How to stop the UITextField from responding to the shake gesture?

对于phonegap,请在AppDelegate.m中的webViewFinishLoad方法中设置此属性

答案 6 :(得分:1)

第一个解决方案

最简单的方法是使用此插件:

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>

答案 7 :(得分:0)

将输入放入iframe,在不需要输入时重新加载iframe。

答案 8 :(得分:0)

我找到了一种始终有效的解决方法:您可以将文本输入托管在框架中。输入完毕后,从页面中删除框架。这似乎可以解决问题。

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/