web-dev-qa-db-ja.com

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

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

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

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

141
LKM

少しいですが、動作するソリューションを見つけました。また、すべての状況で機能するわけではありませんが、私にとっては機能します。ユーザーインターフェイスのサイズを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でこれをテストしましたが、うまくいくようです。

54
LKM

focusoutイベントを使用して、キーボードの解除を検出できます。ぼかしのようなものですが、泡です。キーボードが閉じると起動します(もちろん、他の場合も同様です)。 SafariおよびChromeでは、イベントはaddEventListenerでのみ登録でき、レガシーメソッドでは登録できません。以下は、キーボードを閉じた後にPhonegapアプリを復元するために使用した例です。

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

このスニペットがなければ、アプリコンテナーはページが更新されるまでスクロールされた位置にとどまりました。

31

多分少し良い解決策は、さまざまな入力フィールドで「ぼかし」イベントを(私の場合はjQueryで)バインドすることです。

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

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

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

});

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

15
Michele

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

14
ianh

フォーカスイベントの間、ドキュメントの高さを超えてスクロールでき、魔法のように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です。これは[previous] [next]ツールバーの高さです。

この検出を行うと、ちらつきが少し発生しますが、回避することは不可能と思われます。

11
Hafthor

編集: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では、ビューポートがズーム可能でフォーカスされた入力にスクロールするときに、スクロールとズームとフォーカスの間にバグのある相互作用があるため、他の推奨ソリューション(スクロールトップを変更する)を使用しません(ビューポートの外にフォーカスした入力を残すことができます-表示されます)。

8
robocat

Android 4.1.1でのみテスト:

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

ただし、何らかの理由でキーボードがアップまたはダウンした場合、イベントのサイズ変更は魅力のように機能します。

コーヒー:

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

キーボードが何らかの理由で表示または非表示になったときに起動します。

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

5
user1650613

キーボードを検出する代わりに、ウィンドウのサイズを検出してください

ウィンドウの高さが減少しても、幅が同じ場合、キーボードがオンになっていることを意味します。キーボードがオフになっていない場合は、それに追加して、入力フィールドにフォーカスがあるかどうかをテストすることもできます。

たとえば、このコードを試してください。

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()));
    }   
});     
3
K.A

前の回答で指摘したように、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){ ... }

キーボードが表示されているかどうかを確認します。私はしばらくの間私のウェブアプリでそれを使用してきましたが、それはうまく機能しますが、(他のすべてのソリューションと同様に)「予想される」サイズが適切に更新されないなどの理由で失敗する場合があります。

1
Flow

これを試してください:

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
Nalini Amir

このソリューションはスクロール位置を記憶します

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });
1

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
0
Udo

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

小さな活字で、外部キーボードは現在のブラウザでは現在検出できないことをユーザーに説明します。

0
Ian White

私はこれを自分で試したことはないので、ただのアイデアです...しかし、CSSでメディアクエリを使用して、ウィンドウの高さが変化するタイミングを確認し、そのデザインを変更しようとしましたか? Safariモバイルはキーボードをウィンドウの一部として認識していないので、うまくいけばうまくいくと思います。

例:

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

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

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

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

0
pixelbandito

私はいくつかの検索を行いましたが、「キーボード上に表示」または「キーボード上で却下」のための具体的なものを見つけることができませんでした。 サポートされるイベントの公式リスト を参照してください。 iPadの場合は Technical Note TN2262 も参照してください。おそらく既にご存知のように、ボディイベントonorientationchangeがあります。これを接続して、ランドスケープ/ポートレートを検出できます。

同様に、ワイルドな推測...あなたはサイズ変更を検出しようとしましたか?ビューポートの変更は、表示/非表示されているキーボードから間接的にそのイベントをトリガーする場合があります。

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

これは、サイズ変更イベントで新しい高さを警告するだけです。

0
slf