【问题标题】:How to disable iOS "Shake to Undo" in a webapp如何在 web 应用程序中禁用 iOS“摇动撤消”
【发布时间】:2011-06-29 11:46:05
【问题描述】:

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

谢谢。

【问题讨论】:

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


    【解决方案1】:

    对于 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】:

      这篇博客描述了一个使用 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

      【讨论】:

      • 好主意,但不幸的是没有运气。即使将事件附加(或使用 Zepto 的委托函数)到输入元素本身,撤消对话框仍然会弹出。
      • 哦,不幸的是,将输入设置为只读仍然会弹出对话框。
      • 这不适用于当前版本的 cordova (7.0.1)。 Tobias Christian Jensens 的回答确实很有效。只需将[UIApplication sharedApplication].applicationSupportsShakeToEdit = NO; 添加到Classes/AppDelegate.m 的didFinishLaunchingWithOptions 函数中
      【解决方案3】:

      我最近在开发用户使用 WebSocket 配对设备的游戏时遇到了这个问题。不幸的是,上述解决方案都不起作用。

      简而言之,游戏涉及用户通过手机上的表单订阅频道。订阅后,他们会摇晃设备,然后在他们的桌面上播放一个场景。问题是,只要有人摇晃 iOS 设备,就会弹出“撤消键入”警报。

      这是我为这个问题找到的仅有的两个解决方案。

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

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

      请记住,阻止 keydown 事件传播并不会阻止在现有的 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); 
      

      【讨论】:

      • 感谢分享!我现在无法设置测试用例,但是您的答案似乎经过了很好的研究,并且可以按照我在原始问题中的要求进行,所以如果没有人有,我会接受它作为正确的答案任何反对意见:)
      【解决方案4】:

      Objective-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
      }
      

      【讨论】:

        【解决方案5】:

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

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

        Prevent default Press but not default Drag in iOS MobileSafari?

        【讨论】:

          【解决方案6】:

          见:How to stop the UITextField from responding to the shake gesture?

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

          【讨论】:

            【解决方案7】:

            第一个解决方案

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

            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>
            

            【讨论】:

            • 非常感谢您提供的解决方案 3!正是我想要的!一些表情符号似乎在工作(例如 flash)
            【解决方案8】:

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

            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/

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2020-01-25
                • 2011-02-28
                • 1970-01-01
                • 1970-01-01
                • 2015-03-30
                • 2013-08-01
                • 2011-12-13
                相关资源
                最近更新 更多