【问题标题】:iPad Web App: Detect Virtual Keyboard Using JavaScript in Safari?iPad Web App:在 Safari 中使用 JavaScript 检测虚拟键盘?
【发布时间】:2011-02-05 07:03:37
【问题描述】:

我正在为 iPad 编写一个网络应用程序(不是普通的 App Store 应用程序 - 它是使用 HTML、CSS 和 JavaScript 编写的)。由于键盘占据了屏幕的很大一部分,因此在显示键盘时更改应用程序的布局以适应剩余空间是有意义的。但是,我发现无法检测键盘何时或是否显示。

我的第一个想法是假设当文本字段具有焦点时键盘是可见的。但是,将外部键盘连接到 iPad 时,当文本字段获得焦点时,虚拟键盘不会显示。

在我的实验中,键盘也不会影响任何 DOM 元素的高度或滚动高度,并且我没有发现表明键盘是否可见的专有事件或属性。

【问题讨论】:

  • 嗯,有趣的问题。尝试在 iPad 的 Safari 上迭代“window”的对象,看看是否有任何与键盘支持相关的特殊对象。
  • @David 不行,键盘不是 Javascript“窗口”。
  • @KennyTM。呃。但是在任何窗口的对象中都可能有一个与屏幕键盘显示相关的标志。值得一试。
  • 我试过了。没有找到任何东西,很遗憾。还比较了显示键盘前后三层深度的所有窗口属性。这些差异似乎与键盘指示无关。
  • 这个有更新的答案吗??

标签: javascript iphone ipad safari web-applications


【解决方案1】:

我找到了一个可行的解决方案,虽然它有点难看。它也不会在所有情况下都有效,但它对我有用。由于我正在调整用户界面的大小以适应 iPad 的窗口大小,因此用户通常无法滚动。也就是说,如果我设置了窗口的scrollTop,它将保持为0。

另一方面,如果显示键盘,则滚动突然起作用。所以我可以设置scrollTop,立即测试它的值,然后重置它。下面是使用 jQuery 在代码中的样子:

$(document).ready(function(){
    $('input').bind('focus',function() {
        $(window).scrollTop(10);
        var keyboard_shown = $(window).scrollTop() > 0;
        $(window).scrollTop(0);

        $('#test').append(keyboard_shown?'keyboard ':'nokeyboard ');
    });
});

通常,您会希望用户看不到它。不幸的是,至少在模拟器中运行时,iPad 明显地(虽然很快)再次上下滚动。尽管如此,它仍然有效,至少在某些特定情况下是这样。

我已经在 iPad 上进行了测试,它似乎工作正常。

【讨论】:

  • 我的网络应用程序出现问题,当输入焦点集中在屏幕上时,屏幕会向上滚动一点。我已经禁用了滚动,但仍然可以滚动。有任何想法吗?谢谢 [stackoverflow.com/questions/6740253/…
  • 我还没有尝试过,但看起来很有希望。 .scrollTop(1) 不会同样有效并且不那么明显吗?
  • 这是个坏主意...键盘可能是蓝牙并且虚拟可能不显示。
  • @theSociableme:这个解决方案的重点是正确处理蓝牙键盘。如果您忽略了蓝牙键盘,那么确定是否显示虚拟键盘将很容易,因为您只需检查一个字段是否有焦点。
  • @fraxture:不知道一个全面的解释(如果你研究和写一个,我很想读)。这两个平台在其主要浏览器中处理屏幕键盘的方式非常不同。 Android Chrome 会缩小视口高度以为键盘腾出空间,因此在显示键盘时页面会调整大小。 iOS Safari 用键盘覆盖页面(页面大小保持不变),并改变滚动的工作方式。 Safari 会在视口内滚动页面,同时移动视口,确保在一直向下滚动时页面底部位于键盘上方。
【解决方案2】:

您可以使用 focusout 事件来检测键盘关闭。这就像模糊,但气泡。它会在键盘关闭时触发(当然,在其他情况下也会触发)。在 Safari 和 Chrome 中,只能使用 addEventListener 注册事件,而不能使用传统方法。这是我用来在键盘关闭后恢复 Phonegap 应用程序的示例。

 document.addEventListener('focusout', function(e) {window.scrollTo(0, 0)});

如果没有这个 sn-p,应用容器会一直停留在向上滚动的位置,直到页面刷新。

【讨论】:

  • 我为我的问题找到的最佳解决方案
  • 你也可以使用'focusin'版本来检测键盘是否打开。
  • 不,不幸的是,这并不能解决最初的问题,因为focusout 会在由于任何原因失去焦点时触发。因此,它无助于确定虚拟键盘是否曾经打开过,或者是否使用了外部键盘并且该字段具有焦点而没有使用虚拟键盘。
【解决方案3】:

如果有屏幕键盘,聚焦视口底部附近的文本字段将导致 Safari 将文本字段滚动到视图中。可能有一些方法可以利用这种现象来检测键盘的存在(在页面底部有一个微小的文本字段,可以瞬间获得焦点,或者类似的东西)。

【讨论】:

  • 这是一个巧妙的想法。我找到了一个类似的解决方案,它也使用当前滚动位置来检测虚拟键盘。
  • 太棒了!你拯救了我的一天!
【解决方案4】:

也许更好的解决方案是在各种输入字段上绑定(在我的情况下使用 jQuery)“模糊”事件。

这是因为当键盘消失时,所有表单域都变得模糊。 所以对于我的情况,这个剪断解决了问题。

$('input, textarea').bind('blur', function(e) {

       // Keyboard disappeared
       window.scrollTo(0, 1);

});

希望对您有所帮助。 米歇尔

【讨论】:

  • 感谢您的回答。我发现它有助于解决 iPad Safari 键盘导致 textarea 光标移动(偏移)到 textarea 之外的问题。
【解决方案5】:

在焦点事件期间,您可以滚动超过文档高度,并且 window.innerHeight 会神奇地减少虚拟键盘的高度。请注意,横向和纵向的虚拟键盘大小不同,因此您需要在它发生变化时重新检测它。我建议不要记住这些值,因为用户可以随时连接/断开蓝牙键盘。

var element = document.getElementById("element"); // the input field
var focused = false;

var virtualKeyboardHeight = function () {
    var sx = document.body.scrollLeft, sy = document.body.scrollTop;
    var naturalHeight = window.innerHeight;
    window.scrollTo(sx, document.body.scrollHeight);
    var keyboardHeight = naturalHeight - window.innerHeight;
    window.scrollTo(sx, sy);
    return keyboardHeight;
};

element.onfocus = function () {
    focused = true;
    setTimeout(function() { 
        element.value = "keyboardHeight = " + virtualKeyboardHeight() 
    }, 1); // to allow for orientation scrolling
};

window.onresize = function () {
    if (focused) {
        element.value = "keyboardHeight = " + virtualKeyboardHeight();
    }
};

element.onblur = function () {
    focused = false;
};

请注意,当用户使用蓝牙键盘时,keyboardHeight 为 44,即 [previous][next] 工具栏的高度。

进行此检测时会有一点点闪烁,但似乎无法避免。

【讨论】:

  • 我刚刚在 iOS 8.2 中尝试过,但它不起作用......它在新 iOS 的某个阶段停止工作了吗?
  • 对我也没有用 - 在 iOS9.3 中不会触发调整大小
  • virtualKeyboardHeight 函数帮助我避免滚动离开移动设备上全屏输入的搜索字段。在 iOS 上,当输入字段位于屏幕下方 60% 以内时,它总是被键盘推出屏幕。我尝试过的其他滚动功能根本没有帮助。
【解决方案6】:

编辑:由 Apple 记录,虽然我实际上无法让它工作:WKWebView Behavior with Keyboard Displays:“在 iOS 10 中,WKWebView 对象通过在显示键盘时更新它们的 window.innerHeight 属性来匹配 Safari 的本机行为,并执行不调用调整大小事件”(也许可以使用焦点或焦点加延迟来检测键盘而不是使用调整大小)。

编辑:代码假定屏幕键盘,而不是外部键盘。离开它是因为信息可能对只关心屏幕键盘的其他人有用。使用http://jsbin.com/AbimiQup/4查看页面参数。

我们测试document.activeElement 是否是显示键盘的元素(输入类型=文本、文本区域等)。

以下代码为我们的目的捏造了一些东西(尽管通常不正确)。

function getViewport() {
    if (window.visualViewport && /Android/.test(navigator.userAgent)) {
        // https://developers.google.com/web/updates/2017/09/visual-viewport-api    Note on desktop Chrome the viewport subtracts scrollbar widths so is not same as window.innerWidth/innerHeight
        return {
            left: visualViewport.pageLeft,
            top: visualViewport.pageTop,
            width: visualViewport.width,
            height: visualViewport.height
        };
    }
    var viewport = {
            left: window.pageXOffset,   // http://www.quirksmode.org/mobile/tableViewport.html
            top: window.pageYOffset,
            width: window.innerWidth || documentElement.clientWidth,
            height: window.innerHeight || documentElement.clientHeight
    };
    if (/iPod|iPhone|iPad/.test(navigator.platform) && isInput(document.activeElement)) {       // iOS *lies* about viewport size when keyboard is visible. See http://stackoverflow.com/questions/2593139/ipad-web-app-detect-virtual-keyboard-using-javascript-in-safari Input focus/blur can indicate, also scrollTop: 
        return {
            left: viewport.left,
            top: viewport.top,
            width: viewport.width,
            height: viewport.height * (viewport.height > viewport.width ? 0.66 : 0.45)  // Fudge factor to allow for keyboard on iPad
        };
    }
    return viewport;
}


function isInput(el) {
    var tagName = el && el.tagName && el.tagName.toLowerCase();
    return (tagName == 'input' && el.type != 'button' && el.type != 'radio' && el.type != 'checkbox') || (tagName == 'textarea');
};

上面的代码只是大概的:分体键盘、非对接键盘、物理键盘都是错误的。根据顶部的评论,您可以使用window.innerHeight 属性在 Safari(自 iOS8 起?)或 WKWebView(自 iOS10 起)上的给定代码做得更好。

我在其他情况下发现了失败:例如将焦点放在输入上,然后转到主屏幕,然后返回页面; iPad 不应该让视口变小;旧的 IE 浏览器无法使用,Opera 无法使用,因为 Opera 在键盘关闭后一直专注于元素。

但是,如果视口可缩放(或在首选项中启用强制缩放),标记的答案(更改滚动顶部以测量高度)具有令人讨厌的 UI 副作用。我不使用其他建议的解决方案(更改滚动顶部),因为在 iOS 上,当视口可缩放并滚动到焦点输入时,滚动和缩放和焦点之间存在错误的交互(这可能会在视口之外留下刚刚聚焦的输入 - 不是可见)。

【讨论】:

  • 根据浏览器的 innerHeight 来检测某些元素绝对定位时的全屏中断。一点都不可靠。
【解决方案7】:

仅在 Android 4.1.1 上测试:

blur 事件不是测试键盘上下移动的可靠事件,因为用户可以选择显式隐藏键盘,这不会触发导致键盘显示的字段上的模糊事件。

但是,如果键盘因任何原因向上或向下,调整大小事件就像一个魅力。

咖啡:

$(window).bind "resize", (event) ->  alert "resize"

无论出于何种原因显示或隐藏键盘时都会触发。

但请注意,在 android 浏览器(而不是应用程序)的情况下,有一个可伸缩的 url 栏,当它被收回时不会触发调整大小,但会改变可用的窗口大小。

【讨论】:

  • +1 表示在手动关闭键盘时未触发模糊事件。调整大小是个好主意,它适用于 Android 设备。
  • 可以确认这适用于 iPhone 5 (iOS 6.0.2) 和 iPad 3 (iOS 6.0)。
  • 刚刚在 CrossBrowserTesting 上的 iOS6 上的 Chrome 41 上进行了测试 - 调整大小不会由虚拟键盘的出现或消失触发。
【解决方案8】:

不检测键盘,尝试检测窗口大小

如果窗口的高度降低了,宽度还是一样,就说明键盘是开着的。 否则键盘关闭,您还可以添加,测试任何输入字段是否处于焦点。

试试这个代码。

var last_h = $(window).height(); //  store the intial height.
var last_w = $(window).width(); //  store the intial width.
var keyboard_is_on = false;
$(window).resize(function () {
    if ($("input").is(":focus")) {
        keyboard_is_on =
               ((last_w == $(window).width()) && (last_h > $(window).height()));
    }   
});     

【讨论】:

  • 这在 iOS 8 中似乎不再适用了。键盘覆盖了内容,并且在许多情况下,内容向下滚动,模糊了最初聚焦的输入字段。
  • window height 返回从iOS 7 开始的包括键盘在内的高度,在IOS6 中window.height 会在键盘打开时发生变化。
  • 请注意,当顶部地址栏在滚动时滑入和滑出屏幕时,高度也会发生变化。你应该添加一个最小高度变化,我会说,200px(未经测试)。
【解决方案9】:

这是我创建的一个小型库,您可以使用它来制作 Just Works(TM) 的视口

https://github.com/adamjgrant/a-viewport-that-works

【讨论】:

    【解决方案10】:

    试试这个:

    var lastfoucsin;
    
    $('.txtclassname').click(function(e)
    {
      lastfoucsin=$(this);
    
    //the virtual keyboard appears automatically
    
    //Do your stuff;
    
    });
    
    
    //to check ipad virtual keyboard appearance. 
    //First check last focus class and close the virtual keyboard.In second click it closes the wrapper & lable
    
    $(".wrapperclass").click(function(e)
    {
    
    if(lastfoucsin.hasClass('txtclassname'))
    {
    
    lastfoucsin=$(this);//to avoid error
    
    return;
    
    }
    
    //Do your stuff 
    $(this).css('display','none');
    });`enter code here`
    

    【讨论】:

      【解决方案11】:

      这个想法是在底部添加固定的 div。 当显示/隐藏虚拟键盘时发生滚动事件。 另外,我们找出键盘高度

      const keyboardAnchor = document.createElement('div')
      keyboardAnchor.style.position = 'fixed'
      keyboardAnchor.style.bottom = 0
      keyboardAnchor.style.height = '1px'
      document.body.append(keyboardAnchor)
              
      window.addEventListener('scroll', ev => {
        console.log('keyboard height', window.innerHeight - keyboardAnchor.getBoundingClientRect().bottom)
      }, true)
      
              
              

      【讨论】:

        【解决方案12】:

        visual viewport API 用于对虚拟键盘更改和视口可见性做出反应。

        Visual Viewport API 提供了一种明确的机制来查询和修改窗口的可视视口的属性。视觉视口是屏幕的视觉部分,不包括屏幕键盘、捏拉缩放区域之外的区域或任何其他不随页面尺寸缩放的屏幕工件。

        function viewportHandler() {
          var viewport = event.target;
          console.log('viewport.height', viewport.height)
        }
        
        window.visualViewport.addEventListener('scroll', viewportHandler);
        window.visualViewport.addEventListener('resize', viewportHandler);
        

        【讨论】:

          【解决方案13】:

          此解决方案记住滚动位置

              var currentscroll = 0;
          
              $('input').bind('focus',function() {
                  currentscroll = $(window).scrollTop();
              });
          
              $('input').bind('blur',function() {
                  if(currentscroll != $(window).scrollTop()){
          
                  $(window).scrollTop(currentscroll);
          
                  }
              });
          

          【讨论】:

            【解决方案14】:

            问题在于,即使在 2014 年,设备在软键盘打开时也不一致地处理屏幕调整大小事件和滚动事件。

            我发现,即使您使用的是蓝牙键盘,iOS 也会触发一些奇怪的布局错误;因此,我不必检测软键盘,而只需要定位非常窄且具有触摸屏的设备。

            我使用媒体查询(或window.matchMedia)进行宽度检测,使用Modernizr 进行触摸事件检测。

            【讨论】:

              【解决方案15】:

              正如前面的答案中所述,当键盘出现时,window.innerHeight 变量现在在 iOS10 上得到正确更新,因为我不需要支持早期版本,所以我想出了以下内容破解可能比讨论的“解决方案”更容易。

              //keep track of the "expected" height
              var windowExpectedSize = window.innerHeight;
              
              //update expected height on orientation change
              window.addEventListener('orientationchange', function(){
                  //in case the virtual keyboard is open we close it first by removing focus from the input elements to get the proper "expected" size
                  if (window.innerHeight != windowExpectedSize){
                      $("input").blur();
                      $("div[contentEditable]").blur();     //you might need to add more editables here or you can focus something else and blur it to be sure
                      setTimeout(function(){
                          windowExpectedSize = window.innerHeight;
                      },100);
                  }else{
                      windowExpectedSize = window.innerHeight;
                  }
              });
              
              //and update the "expected" height on screen resize - funny thing is that this is still not triggered on iOS when the keyboard appears
              window.addEventListener('resize', function(){
                  $("input").blur();  //as before you can add more blurs here or focus-blur something
                  windowExpectedSize = window.innerHeight;
              });
              

              那么你可以使用:

              if (window.innerHeight != windowExpectedSize){ ... }
              

              检查键盘是否可见。我已经在我的网络应用程序中使用它一段时间了,它运行良好,但是(与所有其他解决方案一样)您可能会发现它失败的情况是因为“预期”大小未正确更新或其他原因。

              【讨论】:

              • 我希望是这样,但不,它没有得到更新。
              • 不幸的是,在 iOS 14 中,window.innerHeight 似乎不受虚拟键盘状态的影响。
              【解决方案16】:

              也许在您的应用设置中有一个复选框更容易,用户可以在其中切换“已连接外部键盘?”。

              用小字体向用户说明目前在当今的浏览器中无法检测到外部键盘。

              【讨论】:

              • 添加这样的切换是最后的手段,除非没有其他解决方案不会破坏应用程序,否则根本不应该被认为是可接受的。这不应该成为生产正常应用程序的障碍。
              【解决方案17】:

              我进行了一些搜索,但找不到任何具体的“在键盘上显示”或“在键盘上被解雇”。见the official list of supported events。另请参阅 iPad 的 Technical Note TN2262。您可能已经知道,有一个身体事件onorientationchange,您可以连接起来检测横向/纵向。

              类似,但一个疯狂的猜测......你有没有尝试检测调整大小?视口更改可能会通过显示/隐藏键盘间接触发该事件。

              window.addEventListener('resize', function() { alert(window.innerHeight); });
              

              这只会在任何调整大小事件时提醒新高度......

              【讨论】:

              • 很遗憾,在我的测试中,键盘没有触发 resize 事件。
              【解决方案18】:

              我自己没有尝试过,所以这只是一个想法……但是您是否尝试过使用带有 CSS 的媒体查询来查看窗口高度何时发生变化,然后为此更改设计?我想 Safari 移动版没有将键盘识别为窗口的一部分,因此希望可以正常工作。

              例子:

              @media all and (height: 200px){
                  #content {height: 100px; overflow: hidden;}
              }
              

              【讨论】:

              • 非常聪明的主意。不幸的是,在我的测试中,显示键盘并不会影响用于评估媒体查询的高度值。
              • 我可以确认:height: 250px 对我有用(至少在 Android 上)。
              【解决方案19】:

              好吧,您可以检测输入框何时获得焦点,并且您知道键盘的高度。还有可用的 CSS 来获取屏幕的方向,所以我认为你可以破解它。

              不过,您可能希望以某种方式处理物理键盘的情况。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-10-27
                • 2020-04-21
                • 1970-01-01
                • 1970-01-01
                • 2012-06-09
                • 2020-08-31
                • 2015-02-01
                相关资源
                最近更新 更多