iPad Web App:在Safari中使用JavaScript检测虚拟键盘?


147

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

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

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


1
嗯,有趣的问题。尝试遍历iPad Safari上“窗口”的对象,以查看是否有与键盘支持有关的特殊对象。
大卫·默多克

@David无效,键盘不是Javascript“窗口”。
kennytm'4

2
@KennyTM。咄。但是在任何窗口对象中可能都存在与屏幕键盘显示相关的标志。值得一试。
大卫·默多克

1
我试过了 很遗憾,没有找到任何东西。还比较了显示键盘前后三个窗口的所有窗口属性。这些差异似乎都与键盘指示无关。
LKM

3
为此有新的答案吗?
fraxture

Answers:


54

我发现一个可行的解决方案,尽管它有点难看。它也不会在所有情况下都起作用,但是对我有用。由于我正在根据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上对此进行了测试,它似乎可以正常工作。


我的Web应用程序出现问题,当输入集中在屏幕上时,屏幕会向上滚动一点。否则我禁用了滚动,但是仍然可以滚动。有任何想法吗?谢谢[ stackoverflow.com/questions/6740253/...
安德鲁萨穆埃尔森

我还没有尝试过,但是看起来很有希望。不会.scrollTop(1)一样好并且不那么明显吗?
ThinkingStiff

1
这是个坏主意...键盘可能是蓝牙的,并且虚拟的可能无法显示。
theSociableme 2014年

3
@theSociableme:此解决方案的重点是正确处理蓝牙键盘。如果您忽略了蓝牙键盘,那么弄清楚是否显示了虚拟键盘将很容易,因为您可以检查某个字段是否具有焦点。
LKM 2015年

5
@fraxture:不知道全面的解释(如果您研究并编写一个解释,我希望阅读它)。这两个平台在其主浏览器中处理屏幕键盘的方式非常不同。Android Chrome会缩小视口高度以为键盘腾出空间,因此在显示键盘时调整页面大小。iOS Safari使用键盘覆盖页面(页面大小保持不变),并更改滚动方式。Safari既可以在视口内滚动页面,也可以同时移动视口,以确保向下滚动时页面底部位于键盘上方。
LKM

32

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

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

如果没有此代码段,则应用程序容器将保持向上滚动的位置,直到页面刷新为止。


1
我为我的问题找到的最佳解决方案
Sutulustus


1
您也可以使用“ focusin”版本来检测键盘是否打开。
A.Çetin

15

也许更好的解决方案是在各种输入字段上绑定(以jQuery为例)“ blur”事件。

这是因为当键盘消失时,所有表单字段均会模糊。因此,就我的情况而言,此选项解决了问题。

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

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

});

希望能帮助到你。米歇尔


感谢您的回答。我发现解决iPad Safari键盘导致textarea光标移到textarea之外的问题很有用。
肯布罗达(Kennbrodhagen)

14

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


1
这是一个巧妙的想法。我找到了一种类似的解决方案,该解决方案也使用当前滚动位置来检测虚拟键盘。
LKM 2010年

辉煌!您救了我的一天!
aztack

11

在焦点事件期间,您可以滚动超过文档的高度,然后神奇地滚动窗口。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,这是[上一页] [下一页]工具栏的高度。

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


5
我刚刚在iOS 8.2中尝试了此操作,但它不起作用...它是否在某个阶段停止了新iOS的工作?

1
也没有为我工作-在iOS9.3中不会触发调整大小
llamerr

8

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

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

我们测试看是否document.activeElement是显示键盘的元素(输入类型为text,textarea等)。

以下代码为我们的目的捏造了事物(尽管通常不正确)。

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,以在绝对定位某些元素时检测全屏中断。根本不可靠。
乌度

5

仅在Android 4.1.1上测试:

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

但是,如果键盘由于某种原因向上或向下移动,则resize事件可像超级按钮一样工作。

咖啡:

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

无论出于任何原因显示或隐藏键盘,均可在任何时候触发。

但是请注意,在使用Android浏览器(而非应用程序)的情况下,有一个可伸缩的网址栏,该网址栏在收起时不会触发调整大小,但会更改可用窗口的大小。


+1表示模糊事件无法在手动关闭键盘时触发。调整大小是个好主意,它适用于Android设备。
Ankit Garg 2013年

可以确认这在iPhone 5(iOS 6.0.2)和iPad 3(iOS 6.0)上均适用。
迭戈·阿古洛(DiegoAgulló)

1
刚刚在CrossBrowserTesting上的iOS6的Chrome 41上进行了测试-调整大小不会因虚拟键盘的出现或消失而触发。
Dan Dascalescu

4

而不是检测键盘,请尝试检测窗口的大小

如果减小了窗口的高度,并且宽度仍然相同,则表示键盘已打开。否则,您可以在键盘关闭的情况下进行添加,测试是否有任何输入字段处于焦点上。

例如,尝试使用此代码。

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

2
在iOS 8中似乎不再起作用。键盘覆盖了内容,并且在许多情况下,内容向下滚动会遮挡最初集中的输入字段。
里克·斯特拉尔

3
window height返回iOS 7以来IOS6窗口中包括键盘在内的高度。键盘打开时,height确实会改变。
米歇尔2015年

1
请注意,滚动时顶部地址栏滑入和滑出屏幕时,高度也会发生变化。您应该添加200像素(未测试)的最小高度变化。
oriadam '16

1

此解决方案记住滚动位置

    var currentscroll = 0;

    $('input').bind('focus',function() {
        currentscroll = $(window).scrollTop();
    });

    $('input').bind('blur',function() {
        if(currentscroll != $(window).scrollTop()){

        $(window).scrollTop(currentscroll);

        }
    });

1

试试这个:

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`

1

正如前面答案中提到的那样,当键盘出现时,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){ ... }

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


我希望情况确实如此,但是不,它不会更新。
山姆·塞弗隆

0

我进行了一些搜索,但找不到“显示在键盘上”或“关闭键盘上”的任何具体内容。请参阅受支持事件的官方列表。另请参阅适用于iPad的技术说明TN2262。您可能已经知道,可以通过身体事件onorientationchange来检测风景/人像。

同样,但是有一个疯狂的猜测……您是否尝试过检测大小调整?视口的更改可能会通过显示/隐藏键盘间接触发该事件。

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

它将在任何调整大小事件时简单地警告新的高度。


10
不幸的是,在我的测试中,键盘没有触发调整大小事件。
LKM 2010年

0

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

例:

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

2
非常聪明的主意。不幸的是,在我的测试中,显示键盘并没有影响用于评估媒体查询的高度值。
LKM 2010年

我可以确认:高度:250像素对我有效(至少在Android上)。
WoodrowShigeru

0

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

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

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


0

在您的应用程序设置中选中一个复选框,使用户可以切换“是否连接了外部键盘?”可能更容易。

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


1
添加这样的切换是不得已的,除非没有其他解决方案不会破坏应用程序,否则不应视为完全可以接受。这不应该成为生产运行中的应用程序的障碍。
亚当·莱格特

-2

好了,您可以检测输入框何时具有焦点,并且知道键盘的高度。还有CSS可用于获取屏幕方向,因此我认为您可以修改它。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.