iPad Web App:SafariでJavaScriptを使用して仮想キーボードを検出しますか?


147

iPad用のWebアプリを作成しています(通常のApp Storeアプリではなく、 HTML、CSS、JavaScriptを使用して作成されています)。キーボードは画面の大部分を占めるため、キーボードが表示されているときにアプリのレイアウトを変更して、残りのスペースに合わせることは理にかなっています。ただし、キーボードが表示されているかどうか、または表示されているかどうかを検出する方法はありません。

私の最初のアイデアは、テキストフィールドにフォーカスがあるときにキーボードが表示されると想定することでした。ただし、外部キーボードがiPadに接続されている場合、テキストフィールドがフォーカスを受け取ったときに仮想キーボードは表示されません。

私の実験では、キーボードもDOM要素の高さやscrollheightに影響を与えず、キーボードが表示されているかどうかを示す独自のイベントやプロパティも見つかりませんでした。


1
うーん、面白い問題。iPadのSafariで「ウィンドウ」のオブジェクトを繰り返し処理して、キーボードサポートに関連する特別なオブジェクトがないかどうかを確認してください。
デビッドマードック

@Davidは機能しません。キーボードはJavascriptの「ウィンドウ」ではありません。
kennytm 2010

2
@KennyTM。ああ。ただし、ウィンドウのオブジェクトのいずれかに、画面キーボードの表示に関連するフラグが存在する場合があります。それは一撃の価値があります。
David Murdoch

1
やってみました。残念ながら何も見つかりませんでした。また、キーボードを表示する前と後のすべてのウィンドウプロパティを3レベル深く比較しました。違いは、キーボードのインジケータとしては関係がないように思われました。
LKM 2010

3
これに対する新しい答えはありますか?
15

回答:


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

通常、これはユーザーには見えないはずです。残念ながら、少なくともSimulatorで実行しているときは、iPadは目に見えて(すば​​やく)上下にスクロールします。それでも、少なくとも一部の特定の状況では機能します。

これをiPadでテストしましたが、問題なく動作するようです。


入力がフォーカスされていると画面が少し上にスクロールするWebアプリケーションに問題があります。それ以外の場合はスクロールを無効にしましたが、これでもスクロールします。何か案は?おかげで[ stackoverflow.com/questions/6740253/...
アンドリューSamuelsen

私はまだこれを試していませんが、有望に見えます。思いません.scrollTop(1)同じようにうまくいくとあまり目立たないこと?
ThinkingStiff

1
これは悪い考えです...キーボードがBluetoothで仮想が表示されない可能性があります。
theSociableme 2014年

3
@theSociableme:このソリューションの要点は、Bluetoothキーボードを適切に処理することです。Bluetoothキーボードを無視した場合、フィールドにフォーカスがあるかどうかを確認するだけでよいので、仮想キーボードが表示されているかどうかを簡単に判断できます。
LKM

5
@fraxture:包括的な説明がわからない(研究して記述した場合は、ぜひ読んでみたい)。2つのプラットフォームは、メインブラウザーの画面キーボードを非常に異なって処理します。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で)バインドすることです。

これは、キーボードが消えると、すべてのフォームフィールドがぼやけてしまうためです。だから私の状況では、これで問題が解決しました。

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

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

});

それが役に立てば幸い。ミケーレ


この回答をありがとう。iPad Safariキーボードがtextareaカーソルをtextareaの外に移動(オフセット)させる問題を解決するのに役立ちました。
kennbrodhagen、2014年

14

画面キーボードがある場合、ビューポートの下部近くにあるテキストフィールドにフォーカスすると、Safariがテキストフィールドをスクロールして表示します。この現象を利用してキーボードの存在を検出する方法があるかもしれません(ページの下部に小さなテキストフィールドがあり、一時的にフォーカスを取得するか、またはそのようなものです)。


1
それは独創的なアイデアです。現在のスクロール位置を使用して仮想キーボードを検出する同様のソリューションを見つけました。
LKM 2010

素晴らしい!あなたは私の日を救った!
aztack 2013

11

フォーカスイベントの間、ドキュメントの高さを超えてスクロールでき、魔法のようにwindow.innerHeightは仮想キーボードの高さ分減少します。仮想キーボードのサイズは、横向きと縦向きでは異なるため、変更する場合は再検出する必要があります。ユーザーはいつでもBluetoothキーボードを接続/切断できるため、これらの値を覚えておかないことをお勧めします。

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

ユーザーがBluetoothキーボードを使用している場合、keyboardHeightは44 [前へ] [次へ]ツールバーの高さであることに注意してください。

この検出を行うとちらつきが少しありますが、それを回避することは不可能のようです。


5
私はこれをiOS 8.2で試したところ、動作しません...新しいiOSのある段階で動作しなくなりましたか?
Ming

1
私のためにも機能していません-iOS9.3ではサイズ変更は発生しません
llamerr

8

編集:実際に機能させることはできませんでしたが、Appleによって文書化されています:キーボードディスプレイでの WKWebViewの動作:「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が全画面表示の中断を検出することに依存します。まったく信頼できません。
Udo

5

Android 4.1.1でのみテスト:

ユーザーがキーボードを明示的に非表示にするオプションとしてキーボードを表示させたフィールドでぼかしイベントをトリガーしないため、ユーザーはキーボードを上下にテストするためのぼかしイベントは信頼できるイベントではありません。

ただし、何らかの理由でキーボードが上下した場合、サイズ変更イベントはチャームのように機能します。

コーヒー:

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

なんらかの理由でキーボードが表示または非表示になるといつでも起動します。

ただし、Androidブラウザー(アプリではなく)の場合は、格納されているURLバーがあり、格納されているときにサイズ変更を実行しませんが、使用可能なウィンドウサイズを変更します。


手動でキーボードを閉じてもブラーイベントが発生しない+1。サイズ変更は良い考えであり、Androidデバイスでうまく機能します。
Ankit Garg 2013

これがiPhone 5(iOS 6.0.2)とiPad 3(iOS 6.0)の両方で機能することを確認できます。
ディエゴアグロ2013

1
CrossBrowserTestingのiOS6上のChrome 41でテストされました-仮想キーボードの表示または非表示によってサイズ変更がトリガーされません。
Dan Dascalescu、2015

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ではもう機能しないようです。キーボードがコンテンツをオーバーレイし、多くの場合、コンテンツは下にスクロールして、最初にフォーカスされた入力フィールドを覆い隠します。
Rick Strahl、2015

3
ウィンドウの高さは、iOS 7以降のキーボードを含む高さを返します。IOS6のwindow.heightは、キーボードが開いたときに変化します。
ミシエル2015年

1
スクロール時に上部のアドレスバーが画面に出入りするときにも高さが変化することに注意してください。200pxの最小の高さの変更を追加する必要があります(テストされていません)。
oriadam

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アプリでしばらく使用していますが、他のすべてのソリューションと同様に、「期待される」サイズが適切に更新されないなどの理由で失敗する場合があります。


これが事実であることを望んでいましたが、いいえ、更新されません。
Sam Saffron、

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

私は確認できます:高さ:250pxがうまくいきました(少なくともAndroidでは)。
WoodrowShigeru

0

問題は、2014年であっても、ソフトキーボードが開いている間、デバイスが画面サイズ変更イベントとスクロールイベントを一貫して処理しないことです。

Bluetoothキーボードを使用している場合でも、特にiOSは奇妙なレイアウトバグを引き起こすことがわかりました。そのため、ソフトキーボードを検出する代わりに、非常に幅が狭くタッチスクリーンを備えたデバイスをターゲットにする必要がありました。

幅の検出にはメディアクエリ(またはwindow.matchMedia)を使用し、タッチイベントの検出にはModernizrを使用します。


0

おそらく、ユーザーが「外部キーボードを接続しましたか?」を切り替えることができるチェックボックスをアプリの設定に置く方が簡単です。

現在、外付けキーボードは現在のブラウザでは検出できないことを、細かい部分でユーザーに説明します。


1
このようなトグルを追加することは、アプリを壊さない他の解決策がない限り、まったく許容できないと考えられる最後の手段です。これは、機能するアプリを作成するためのブロッカーになるべきものではありません。
Adam Leggett

-2

さて、入力ボックスにフォーカスがあることを検出でき、キーボードの高さがわかります。画面の向きを取得するためのCSSもありますので、ハッキングできると思います。

ただし、物理的なキーボードの場合はどうにかして処理する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.