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

时间:2010-04-07 14:12:24

标签: javascript iphone ipad safari web-applications

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

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

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

21 个答案:

答案 0 :(得分:53)

我找到了一个有效的解决方案,虽然它有点难看。它也不适用于所有情况,但它适用于我。由于我正在调整用户界面的大小到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上对此进行了测试,看起来效果很好。

答案 1 :(得分:30)

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

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

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

答案 2 :(得分:15)

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

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

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

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

});
希望它有所帮助。 米歇尔

答案 3 :(得分:14)

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

答案 4 :(得分:11)

在焦点事件期间,您可以滚动文档高度并神奇地滚动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]工具栏的高度。

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

答案 5 :(得分:8)

编辑:由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副作用。我没有使用其他建议的解决方案(更改scrolltop),因为在iOS上,当视口可缩放并滚动到聚焦输入时,滚动和滚动之间存在错误的交互。变焦&焦点(可以在视口外留下一个刚刚聚焦的输入 - 不可见)。

答案 6 :(得分:5)

仅在Android 4.1.1上测试过:

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

然而,如果键盘因任何原因上升或下降,

调整大小事件就像魅力一样。

咖啡:

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

在出于任何原因显示或隐藏键盘的任何时候都会触发。

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

答案 7 :(得分:3)

尝试检测窗口的大小

,而不是检测键盘

如果窗口高度减小,宽度仍然相同,则表示键盘已打开。 否则键盘关闭,你也可以添加它,测试任何输入字段是否在焦点上。

请尝试使用此代码。

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

答案 8 :(得分:1)

此解决方案会记住滚动位置

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });

答案 9 :(得分:1)

这个想法是在底部添加固定的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)

        
        

答案 10 :(得分: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`

答案 11 :(得分:1)

正如之前的答案所述,当键盘出现时, window.innerHeight变量现在在iOS10上正确更新,因为我不需要对早期版本的支持我想出了以下hack可能比讨论的#34;解决方案更容易一些。

network

然后你可以使用:

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

检查键盘是否可见。我已经在我的网络应用程序中使用它已经有一段时间它运行良好,但是(正如所有其他解决方案一样)你可能会发现它失败的情况,因为"期望"尺寸没有正确更新或其他东西。

答案 12 :(得分:1)

在2019年对此进行回答。

在iOS 12上,我没有看到window.innerHeight随键盘是否显示而变化。这与本机WKWebView行为一致,该行为只是将视图的一部分推到屏幕外而不是调整其大小(我相信这是Android的行为)。

我一直成功的唯一方法就是创建一个固定位置元素并检查其位置。必须在位置检查之前的某个时间创建元素。通常是在加载时创建一次,以后再进行检查。

var testElement = document.createElement('p');
testElement.style.position = 'fixed';

function isKeyboardVisible() {
  testElement.style.top = 0;
  return !!testElement.offsetTop;
}

setTimeout(function() {
  document.write(isKeyboardVisible() ?
    'Keyboard is visible' :
    'Keyboard is not visisble');
}, 1000);
<input type="text">

答案 13 :(得分:0)

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

答案 14 :(得分:0)

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

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

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

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

答案 15 :(得分:0)

这是我创建的一个小库,可用于制作Just Works(TM)的视口

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

答案 16 :(得分:0)

在Safari浏览器上,当元素位于屏幕底部且虚拟键盘可见时,该位置将增加约1像素。您可以利用它。

假设它是横向模式下的移动设备

<div id="detector" style="position: absolute; bottom: 0"></div>

const detector = document.querySelector('#detector');
detector.getBoundingClientRect().bottom // 320

// when virtual keyboard is visible
detector.getBoundingClientRect().bottom // 329 or 328

答案 17 :(得分:0)

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

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

答案 18 :(得分:0)

问题在于,即使在2014年,设备也会在软键盘打开时处理屏幕调整大小事件以及滚动事件。

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

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

答案 19 :(得分:0)

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

示例:

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

答案 20 :(得分:-1)

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

但是你想要以某种方式处理物理键盘的情况。