Aplikasi Web iPad: Deteksi Keyboard Virtual Menggunakan JavaScript di Safari?

147

Saya sedang menulis aplikasi web untuk iPad ( bukan aplikasi App Store biasa - ini ditulis menggunakan HTML, CSS, dan JavaScript). Karena keyboard mengisi sebagian besar layar, masuk akal untuk mengubah tata letak aplikasi agar sesuai dengan ruang yang tersisa saat keyboard ditampilkan. Namun, saya tidak menemukan cara untuk mendeteksi kapan atau apakah keyboard ditampilkan.

Ide pertama saya adalah berasumsi bahwa keyboard terlihat ketika bidang teks memiliki fokus. Namun, ketika keyboard eksternal terpasang ke iPad, keyboard virtual tidak muncul ketika bidang teks menerima fokus.

Dalam percobaan saya, keyboard juga tidak memengaruhi ketinggian atau gulir dari elemen DOM mana pun, dan saya tidak menemukan peristiwa atau properti khusus yang menunjukkan apakah keyboard terlihat.

LKM
sumber
1
Hm, masalah yang menarik. Coba iterasi di atas objek "jendela" di Safari iPad untuk melihat apakah ada objek khusus yang terkait dengan dukungan keyboard.
David Murdoch
@ David yang tidak akan berfungsi, keyboard bukan "jendela" Javascript.
kennytm
2
@ KennyTM. Duh. Tetapi mungkin ada bendera yang terkait dengan tampilan keyboard di layar di objek jendela mana pun. Layak dicoba.
David Murdoch
1
Saya mencobanya. Sayangnya, tidak menemukan apa pun. Juga membandingkan semua properti jendela sedalam tiga level sebelum dan sesudah memperlihatkan keyboard. Tidak ada perbedaan yang tampak relevan sebagai indikator untuk keyboard.
LKM
3
Apakah ada jawaban yang lebih baru untuk ini ??
Kelemahan

Jawaban:

54

Saya menemukan solusi yang berfungsi, meskipun agak jelek. Itu juga tidak akan berfungsi dalam setiap situasi, tetapi itu bekerja untuk saya. Karena saya mengadaptasi ukuran antarmuka pengguna dengan ukuran jendela iPad, pengguna biasanya tidak dapat menggulir. Dengan kata lain, jika saya mengatur scrollTop jendela, itu akan tetap pada 0.

Jika, di sisi lain, keyboard ditampilkan, menggulir tiba-tiba berfungsi. Jadi saya dapat mengatur scrollTop, segera menguji nilainya, dan kemudian mengatur ulang. Begini caranya yang terlihat dalam kode, menggunakan 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 ');
    });
});

Biasanya, Anda berharap ini tidak terlihat oleh pengguna. Sayangnya, setidaknya saat berjalan di Simulator, iPad terlihat (meskipun cepat) menggulir ke atas dan ke bawah lagi. Tetap bekerja, setidaknya dalam beberapa situasi tertentu.

Saya sudah menguji ini di iPad, dan sepertinya berfungsi baik.

LKM
sumber
Saya mengalami masalah dengan aplikasi web saya di mana saat input difokuskan, layar akan sedikit bergulir. Kalau tidak, saya telah menonaktifkan pengguliran, tetapi masih menggulir ini. Ada ide? Terima kasih [ stackoverflow.com/questions/6740253/...
Andrew Samuelsen
Saya belum mencoba ini, tetapi terlihat menjanjikan. Tidak akan .scrollTop(1)bekerja dengan baik dan menjadi kurang jelas?
ThinkingStiff
1
Ini ide yang buruk ... Keyboard mungkin bluetooth dan virtual mungkin tidak ditampilkan.
theSociableme
3
@theSociableme: Inti dari solusi ini adalah untuk menangani keyboard bluetooth dengan benar. Jika Anda mengabaikan keyboard bluetooth, mencari tahu apakah keyboard virtual ditampilkan akan mudah, karena Anda bisa memeriksa apakah suatu bidang memiliki fokus.
LKM
5
@Fraxture: Tidak tahu penjelasan yang komprehensif (jika Anda meneliti dan menulis satu, saya ingin membacanya). Kedua platform menangani keyboard layar di browser utama mereka sangat berbeda. Android Chrome mengecilkan ketinggian viewport untuk memberikan ruang bagi keyboard, sehingga halaman mengubah ukuran saat keyboard ditampilkan. iOS Safari menutupi halaman dengan keyboard (ukuran halaman tetap sama), dan mengubah cara kerja gulir. Safari menggulir halaman di dalam viewport, dan secara bersamaan memindahkan viewport, memastikan bahwa bagian bawah halaman berada di atas keyboard ketika digulirkan sepenuhnya ke bawah.
LKM
32

Anda dapat menggunakan acara fokus untuk mendeteksi pemberhentian keyboard. Ini seperti kabur, tetapi gelembung. Ini akan menyala ketika keyboard ditutup (tetapi juga dalam kasus lain, tentu saja). Di Safari dan Chrome acara hanya dapat didaftarkan dengan addEventListener, bukan dengan metode lawas. Berikut adalah contoh yang saya gunakan untuk mengembalikan aplikasi Phonegap setelah keyboard diberhentikan.

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

Tanpa cuplikan ini, wadah aplikasi tetap berada di posisi atas-bawah sampai halaman refresh.

Per Dicari Aronsson
sumber
1
perbaikan terbaik yang saya temukan untuk masalah saya
Sutulustus
1
Anda juga dapat menggunakan, versi 'focusin' untuk mendeteksi keyboard terbuka.
A.Çetin
15

mungkin solusi yang sedikit lebih baik adalah untuk mengikat (dengan jQuery dalam kasus saya) peristiwa "blur" pada berbagai bidang input.

Ini karena ketika keyboard menghilang semua bidang formulir buram. Jadi untuk situasi saya, ini snipped memecahkan masalah.

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

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

});

semoga membantu. Michele

Michele
sumber
Terima kasih atas jawaban ini. Saya merasa berguna untuk menyelesaikan masalah ketika keyboard iPad Safari menyebabkan kursor textarea dipindahkan (diimbangi) di luar textarea.
kennbrodhagen
14

Jika ada keyboard di layar, memfokuskan bidang teks yang berada di dekat bagian bawah viewport akan menyebabkan Safari menggulir bidang teks ke dalam tampilan. Mungkin ada beberapa cara untuk mengeksploitasi fenomena ini untuk mendeteksi keberadaan keyboard (memiliki bidang teks kecil di bagian bawah halaman yang mendapatkan fokus sesaat, atau sesuatu seperti itu).

ianh
sumber
1
Itu ide yang cerdik. Saya menemukan solusi serupa yang juga menggunakan posisi gulir saat ini untuk mendeteksi keyboard virtual.
LKM
brilian! kamu menyelamatkan hariku!
aztack
11

Selama acara fokus, Anda dapat menggulir melewati ketinggian dokumen dan secara ajaib window.innerHeight dikurangi oleh ketinggian keyboard virtual. Perhatikan bahwa ukuran keyboard virtual berbeda untuk orientasi lanskap vs potret sehingga Anda harus mengarahkan ulang ketika itu berubah. Saya akan menyarankan untuk tidak mengingat nilai-nilai ini karena pengguna dapat menghubungkan / memutuskan koneksi keyboard bluetooth kapan saja.

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

Perhatikan bahwa ketika pengguna menggunakan keyboard bluetooth, keyboardHeight adalah 44 yang merupakan ketinggian toolbar [sebelumnya] [berikutnya].

Ada sedikit kedipan ketika Anda melakukan deteksi ini, tetapi sepertinya tidak mungkin untuk menghindarinya.

Hafthor
sumber
5
Saya baru saja mencoba ini di iOS 8.2 dan tidak berhasil ... apakah ia berhenti bekerja pada tahap tertentu untuk iOS baru?
Ming
1
Saya juga tidak bekerja untuk saya - mengubah ukuran tidak dipecat di iOS9.3
llamerr
8

Sunting: Didokumentasikan oleh Apple walaupun saya tidak bisa membuatnya berfungsi: Perilaku WKWebView dengan Menampilkan Keyboard : "Di iOS 10, objek WKWebView cocok dengan perilaku asli Safari dengan memperbarui properti window.innerHeight ketika keyboard ditampilkan, dan jangan menelepon mengubah ukuran acara "(mungkin dapat menggunakan fokus atau fokus plus penundaan untuk mendeteksi keyboard alih-alih menggunakan pengubahan ukuran).

Sunting: kode menganggap keyboard layar, bukan keyboard eksternal. Membiarkannya karena info mungkin berguna bagi orang lain yang hanya peduli pada keyboard layar. Gunakan http://jsbin.com/AbimiQup/4 untuk melihat params halaman.

Kami menguji untuk melihat apakah document.activeElementelemen tersebut menunjukkan keyboard (tipe input = teks, textarea, dll).

Kode berikut menipu hal-hal untuk tujuan kita (meskipun secara umum tidak benar).

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

Kode di atas hanya perkiraan: Itu salah untuk keyboard terbagi, keyboard tidak terkunci, keyboard fisik. Sesuai komentar di atas, Anda mungkin dapat melakukan pekerjaan yang lebih baik daripada kode yang diberikan pada Safari (sejak iOS8?) Atau WKWebView (sejak iOS10) menggunakan window.innerHeightproperti.

Saya telah menemukan kegagalan dalam kondisi lain: misalnya fokus pada input, lalu buka layar beranda lalu kembali ke halaman; iPad seharusnya tidak membuat viewport lebih kecil; browser IE lama tidak akan berfungsi, Opera tidak berfungsi karena Opera tetap fokus pada elemen setelah keyboard ditutup.

Namun jawaban yang ditandai (mengubah scrolltop untuk mengukur ketinggian) memiliki efek samping UI yang buruk jika viewport diperbesar (atau dipaksa-zoom diaktifkan dalam preferensi). Saya tidak menggunakan solusi yang disarankan lainnya (mengubah scrolltop) karena di iOS, ketika viewport diperbesar dan bergulir ke input yang difokuskan, ada interaksi buggy antara scrolling & zoom & fokus (yang dapat meninggalkan input yang fokus hanya di luar viewport - tidak terlihat).

Robocat
sumber
Tergantung pada innerHeight browser untuk mendeteksi jeda layar penuh ketika beberapa elemen diposisikan secara absolut. Tidak bisa diandalkan sama sekali.
Udo
5

Hanya diuji pada Android 4.1.1:

blur event bukanlah acara yang dapat diandalkan untuk menguji keyboard atas dan ke bawah karena pengguna sebagai opsi untuk menyembunyikan keyboard secara eksplisit yang tidak memicu peristiwa blur pada bidang yang menyebabkan keyboard ditampilkan.

Namun, mengubah ukuran acara berfungsi seperti pesona jika keyboard naik atau turun karena alasan apa pun.

kopi:

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

menyala kapan saja keyboard ditampilkan atau disembunyikan karena alasan apa pun.

Namun perlu dicatat dalam kasus peramban android (bukan aplikasi) ada bilah url yang dapat ditarik yang tidak memecat ukurannya saat ditarik kembali tetapi tidak mengubah ukuran jendela yang tersedia.

pengguna1650613
sumber
+1 untuk acara blur yang tidak aktif saat mengabaikan keyboard secara manual. Ubah ukuran adalah ide yang bagus dan itu akan bekerja dengan baik untuk perangkat Android.
Ankit Garg
Dapat mengonfirmasi bahwa ini berfungsi pada iPhone 5 (iOS 6.0.2) dan iPad 3 (iOS 6.0).
Diego Agull
1
Baru saja diuji pada Chrome 41 di iOS6 pada CrossBrowserTesting - resize tidak dipicu oleh keyboard virtual yang muncul atau menghilang.
Dan Dascalescu
4

Alih-alih mendeteksi keyboard, cobalah untuk mendeteksi ukuran jendela

Jika ketinggian jendela dikurangi, dan lebarnya masih sama, itu berarti keyboard menyala. Jika keyboard tidak aktif, Anda juga dapat menambahkannya, menguji apakah ada bidang input yang fokus atau tidak.

Coba kode ini misalnya.

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()));
    }   
});     
KA
sumber
2
Itu tampaknya tidak berfungsi lagi di iOS 8. Papan tombol menindih konten dan dalam banyak kasus, konten bergulir ke bawah mengaburkan bidang input awalnya fokus.
Rick Strahl
3
tinggi jendela mengembalikan ketinggian termasuk keyboard sejak iOS 7, di jendela IOS6. ketinggian berubah ketika keyboard terbuka.
Michiel
1
Perhatikan bahwa ketinggian juga berubah ketika bilah alamat atas masuk dan keluar dari layar saat menggulir. Anda harus menambahkan perubahan ketinggian minimum, saya katakan, 200px (tidak diuji).
oriadam
1

Solusi ini mengingat posisi gulir

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });
WebsterDevelopine
sumber
1

Coba yang ini:

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`
Nalini Amir
sumber
1

Seperti disebutkan dalam jawaban sebelumnya di suatu tempat variabel window.innerHeight akan diperbarui dengan benar sekarang di iOS10 ketika keyboard muncul dan karena saya tidak memerlukan dukungan untuk versi sebelumnya, saya membuat hack berikut yang mungkin sedikit lebih mudah daripada yang dibahas "solusi".

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

maka Anda dapat menggunakan:

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

untuk memeriksa apakah keyboard terlihat. Saya telah menggunakannya untuk sementara waktu sekarang di aplikasi web saya dan berfungsi dengan baik, tetapi (karena semua solusi lain) Anda mungkin menemukan situasi di mana ia gagal karena ukuran "yang diharapkan" tidak diperbarui dengan benar atau sesuatu.

Mengalir
sumber
Saya berharap ini yang terjadi, tetapi tidak, itu tidak diperbarui.
Sam Saffron
0

Saya melakukan pencarian, dan saya tidak dapat menemukan sesuatu yang konkret untuk "pada keyboard yang ditampilkan" atau "pada keyboard yang dihapus". Lihat daftar resmi acara yang didukung . Juga lihat Catatan Teknis TN2262 untuk iPad. Seperti yang mungkin sudah Anda ketahui, ada acara tubuh yang onorientationchangedapat Anda pasang untuk mendeteksi lanskap / potret.

Demikian pula, tetapi tebakan liar ... sudahkah Anda mencoba mendeteksi ukuran? Perubahan viewport dapat memicu peristiwa itu secara tidak langsung dari keyboard yang ditampilkan / disembunyikan.

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

Yang hanya akan mengingatkan ketinggian baru pada acara pengubahan ukuran ....

slf
sumber
10
Sayangnya, dalam pengujian saya, keyboard tidak memicu acara pengubahan ukuran.
LKM
0

Saya belum mencoba ini sendiri, jadi ini hanya sebuah ide ... tetapi apakah Anda sudah mencoba menggunakan pertanyaan media dengan CSS untuk melihat kapan ketinggian jendela berubah dan kemudian mengubah desain untuk itu? Saya akan membayangkan bahwa Safari mobile tidak mengenali keyboard sebagai bagian dari jendela sehingga diharapkan akan berfungsi.

Contoh:

@media all and (height: 200px){
    #content {height: 100px; overflow: hidden;}
}
Janae
sumber
2
Ide yang sangat pintar. Sayangnya, dalam pengujian saya, menampilkan keyboard tidak memengaruhi nilai ketinggian yang digunakan untuk mengevaluasi kueri media.
LKM
Saya dapat mengonfirmasi: tinggi: 250px bekerja untuk saya (setidaknya di Android).
WoodrowShigeru
0

Masalahnya adalah bahwa, bahkan pada tahun 2014, perangkat menangani acara pengubahan ukuran layar, serta acara gulir, tidak konsisten saat keyboard lunak terbuka.

Saya telah menemukan bahwa, bahkan jika Anda menggunakan keyboard bluetooth, iOS secara khusus memicu beberapa bug tata letak yang aneh; jadi alih-alih mendeteksi keyboard yang lunak, saya hanya harus menargetkan perangkat yang sangat sempit dan memiliki layar sentuh.

Saya menggunakan kueri media (atau window.matchMedia ) untuk deteksi lebar dan Modernizr untuk deteksi acara sentuh.

pixelbandito
sumber
0

Mungkin lebih mudah untuk memiliki kotak centang di pengaturan aplikasi Anda di mana pengguna dapat beralih 'keyboard eksternal terpasang?'.

Dalam cetakan kecil, jelaskan kepada pengguna bahwa keyboard eksternal saat ini tidak terdeteksi di peramban saat ini.

Ian White
sumber
1
Menambahkan toggle seperti ini adalah pilihan terakhir yang tidak dapat dianggap dapat diterima sama sekali kecuali tidak ada solusi lain yang tidak akan merusak aplikasi. Ini bukan sesuatu yang harus menjadi pemblokir untuk menghasilkan aplikasi yang berfungsi.
Adam Leggett
-2

Nah, Anda dapat mendeteksi kapan kotak input Anda memiliki fokus, dan Anda tahu ketinggian keyboard. Ada juga CSS yang tersedia untuk mendapatkan orientasi layar, jadi saya pikir Anda bisa meretasnya.

Anda tentu ingin menangani casing keyboard fisik.

stuntmouse
sumber