iPad Web Uygulaması: Safari'de JavaScript Kullanarak Sanal Klavye Algılandı mı?


150

İPad için bir web uygulaması yazıyorum ( normal bir App Store uygulaması değil - HTML, CSS ve JavaScript kullanılarak yazılmıştır). Klavye ekranın büyük bir bölümünü kapladığından, klavye gösterildiğinde uygulamanın düzenini kalan alana sığacak şekilde değiştirmek mantıklı olacaktır. Ancak, klavyenin ne zaman gösterilip gösterilmediğini algılamanın bir yolunu bulamadım.

İlk fikrim, bir metin alanı odaklandığında klavyenin görünür olduğunu varsaymaktı. Ancak, bir iPad'e harici bir klavye takıldığında, bir metin alanı odak aldığında sanal klavye görünmez.

Deneylerimde klavye, DOM öğelerinin hiçbirinin yüksekliğini veya kaydırma yüksekliğini etkilemedi ve klavyenin görünür olup olmadığını gösteren hiçbir tescilli olay veya özellik bulamadım.


1
Hm, ilginç sorun. Klavye desteğiyle ilgili herhangi bir özel nesne olup olmadığını görmek için iPad'in Safari'deki "pencere" nesnelerinin üzerinde yinelemeyi deneyin.
David Murdoch

@David çalışmaz, klavye bir Javascript "penceresi" değildir.
kennytm

2
@KennyTM. Duh. Ancak, pencerenin herhangi bir nesnesinde ekran klavyesi görüntüsüyle ilgili bir bayrak olabilir. Denemeye değer.
David Murdoch

1
Bunu denedim. Maalesef bir şey bulamadım. Ayrıca, tüm pencere özelliklerini klavyeyi göstermeden önce ve sonra üç düzey derinlikte karşılaştırdı. Farklılıkların hiçbiri klavye için gösterge olarak alakalı görünmüyordu.
LKM

3
Bunun için daha yeni bir cevap var mı?
fraxture

Yanıtlar:


54

Biraz çirkin olmasına rağmen çalışan bir çözüm buldum. Ayrıca her durumda işe yaramayacak ama benim için çalışıyor. Kullanıcı arayüzünün boyutunu iPad'in pencere boyutuna uyarladığım için, kullanıcı normalde kaydırma yapamıyor. Başka bir deyişle, pencerenin scrollTop değerini ayarlarsam, 0'da kalacaktır.

Öte yandan, klavye gösterilirse, kaydırma işlemi aniden çalışır. Böylece scrollTop'ı ayarlayabilir, değerini hemen test edebilir ve ardından sıfırlayabilirim. JQuery kullanarak kodda şöyle görünebilir:

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

Normalde, bunun kullanıcı tarafından görülmemesini beklersiniz. Ne yazık ki, en azından Simülatörde çalışırken, iPad gözle görülür şekilde (hızlı olsa da) tekrar yukarı ve aşağı kayar. Yine de, en azından bazı özel durumlarda işe yarıyor.

Bunu bir iPad'de test ettim ve iyi çalışıyor gibi görünüyor.


Web uygulamamda, giriş odaklandığında ekranın biraz yukarı kaydığı bir sorun yaşıyorum. Aksi takdirde kaydırmayı devre dışı bıraktım, ancak yine de bu kaydırılıyor. Herhangi bir fikir? Teşekkürler [ stackoverflow.com/questions/6740253/…
Andrew Samuelsen

Henüz denemedim ama umut verici görünüyor. .scrollTop(1)Aynı şekilde işe yaramaz ve daha az belirgin olmaz mı?
ThinkingStiff

1
Bu kötü bir fikir ... Klavye bluetooth olabilir ve sanal görüntülenmeyebilir.
theSociableme

3
@theSociableme: Bu çözümün tüm amacı, bluetooth klavyeyi doğru şekilde kullanmaktır. Bluetooth klavyeleri görmezden gelirseniz, sanal klavyenin gösterilip gösterilmediğini anlamak kolay olurdu, çünkü bir alanın odaklanıp odaklanmadığını kontrol edebilirsiniz.
LKM

5
@fraxture: Kapsamlı bir açıklama bilmiyorum (araştırıp yazarsanız, okumak isterim). İki platform, ana tarayıcılarında ekran klavyelerini çok farklı şekilde kullanır. Android Chrome, klavye için yer açmak için görüntü alanı yüksekliğini küçültür, böylece klavye gösterildiğinde sayfa yeniden boyutlandırılır. iOS Safari, klavyeyle sayfayı kaplar (sayfa boyutu aynı kalır) ve kaydırmanın çalışma şeklini değiştirir. Safari hem sayfayı görüntü alanı içinde kaydırır hem de eşzamanlı olarak görüntü alanını hareket ettirerek, tamamen aşağı kaydırıldığında sayfanın alt kısmının klavyenin üzerinde olmasını sağlar.
LKM

33

Klavyenin kapatılmasını algılamak için odaklanma olayını kullanabilirsiniz. Bulanık gibi ama kabarcıklar. Klavye kapandığında ateşlenecektir (ama tabii ki diğer durumlarda da). Safari ve Chrome'da etkinlik, eski yöntemlerle değil, yalnızca addEventListener ile kaydedilebilir. İşte klavye kapatıldıktan sonra Phonegap uygulamasını geri yüklemek için kullandığım bir örnek.

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

Bu snippet olmadan, uygulama kapsayıcısı sayfa yenilenene kadar yukarı kaydırılmış konumda kaldı.


1
sorunum için bulduğum en iyi düzeltme
Sutulustus


1
Ayrıca, klavyenin açık olduğunu algılamak için 'focusin' sürümünü de kullanabilirsiniz.
A.Çetin

15

belki biraz daha iyi bir çözüm (benim durumumda jQuery ile) çeşitli girdi alanlarına "bulanıklaştırma" olayını bağlamaktır.

Bunun nedeni, klavye kaybolduğunda tüm form alanlarının bulanık olmasıdır. Yani benim durumum için bu kesilen sorun sorunu çözdü.

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

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

});

Umarım yardımcı olur. Michele


Bu cevap için teşekkürler. İPad Safari klavyesinin metin alanı imlecinin metin alanının dışına çıkmasına (kaymasına) neden olduğu bir sorunu çözmenin faydalı olduğunu gördüm.
kennbrodhagen

14

Bir ekran klavyesi varsa, görüntü alanının altına yakın bir metin alanına odaklanmak, Safari'nin metin alanını görünüme kaydırmasına neden olur. Klavyenin varlığını saptamak için bu fenomenden yararlanmanın bir yolu olabilir (sayfanın alt kısmında anlık olarak odaklanan küçük bir metin alanı veya buna benzer bir şey).


1
Bu dahice bir fikir. Sanal klavyeyi algılamak için geçerli kaydırma konumunu da kullanan benzer bir çözüm buldum.
LKM

harika! günümü kurtardın!
aztack

12

Odaklanma olayı sırasında belge yüksekliğini geçebilir ve sihirli bir şekilde window.innerHeight sanal klavyenin yüksekliği kadar azaltılır. Sanal klavyenin boyutunun yatay ve dikey yönler için farklı olduğunu, bu nedenle değiştiğinde yeniden algılamanız gerekeceğini unutmayın. Kullanıcı herhangi bir zamanda bir bluetooth klavyeyi bağlayabileceği / bağlantısını kesebileceği için bu değerleri hatırlamamanızı tavsiye ederim.

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

Kullanıcı bir bluetooth klavye kullanırken, keyboardHeight değerinin [önceki] [sonraki] araç çubuğunun yüksekliği olan 44 olduğunu unutmayın.

Bu algılamayı yaptığınızda ufak bir titreme oluyor, ancak bundan kaçınmak mümkün görünmüyor.


5
Bunu iOS 8.2'de yeni denedim ve işe yaramıyor ... yeni iOS için bir aşamada çalışmayı bıraktı mı?
Ming

1
Benim için de çalışmadım
iOS9.3'te

VirtualKeyboardHeight işlevi, yazıldığında mobil cihazlarda tam ekrana giden bir arama alanından uzaklaşmaktan kaçınmama yardımcı oldu. Giriş alanı ekranın% 60'ının altındayken, klavye tarafından her zaman iOS'ta ekrandan dışarı itildi. Denediğim diğer kaydırma işlevleri hiç yardımcı olmadı.
helicon

9

Düzenleme: Apple tarafından belgelendi, ancak aslında çalışmasını sağlayamadım: Klavye Ekranlarıyla WKWebView Davranışı : "iOS 10'da, WKWebView nesneleri klavye gösterildiğinde window.innerHeight özelliğini güncelleyerek Safari'nin yerel davranışıyla eşleşir ve arama yapmaz olayları yeniden boyutlandırma "(klavyeyi algılamak için yeniden boyutlandırma kullanmak yerine odak veya odak artı gecikme kullanabilir).

Düzenleme: kod, harici klavyeyi değil, ekran klavyesini varsayar. Bırakmak, çünkü bilgi yalnızca ekran klavyelerini önemseyen başkaları için yararlı olabilir. Sayfa parametrelerini görüntülemek için http://jsbin.com/AbimiQup/4 kullanın .

document.activeElementKlavyeyi gösteren bir öğe olup olmadığını görmek için test ederiz (giriş türü = metin, metin alanı, vb.).

Aşağıdaki kod, bizim amaçlarımız için bir şeyleri uydurur (genel olarak doğru olmasa da).

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

Yukarıdaki kod yalnızca yaklaşıktır: Bölünmüş klavye, kilitlenmemiş klavye, fiziksel klavye için yanlıştır. Üstteki yoruma göre, window.innerHeightözelliği kullanarak Safari'de (iOS8'den beri?) Veya WKWebView'da (iOS10'dan beri) verilen koddan daha iyi bir iş yapabilirsiniz .

Diğer koşullar altında hatalar buldum: örneğin, girişe odaklanın, sonra ana ekrana gidin ve sonra sayfaya geri dönün; iPad, görüntü alanını küçültmemelidir; eski IE tarayıcıları çalışmıyor, Opera klavye kapandıktan sonra öğeye odaklanmaya devam ettiği için çalışmadı.

Bununla birlikte, görüntü alanı yakınlaştırılabiliyorsa (veya tercihlerde zorla yakınlaştırma etkinse) etiketli yanıtın (kaydırma çubuğunun yüksekliği ölçmek için değiştirilmesi) kullanıcı arabirimi yan etkileri vardır. Önerilen diğer çözümü (kaydırma üstünü değiştirme) kullanmıyorum çünkü iOS'ta, görüntü alanı yakınlaştırılabildiğinde ve odaklanmış girdiye kaydırıldığında, kaydırma, yakınlaştırma ve odaklanma arasında hatalı etkileşimler vardır (bu, yalnızca odaklanmış bir girdiyi görüntü alanının dışında bırakabilir - değil gözle görülür).


Bazı öğeler kesinlikle konumlandırıldığında tam ekran kesintilerini algılamak için innerHeight tarayıcılarına bağlı olarak. Hiç güvenilir değil.
Udo

5

Yalnızca Android 4.1.1'de test edilmiştir:

Bulanıklaştırma olayı, klavyeyi yukarı ve aşağı test etmek için güvenilir bir olay değildir, çünkü kullanıcı klavyeyi açıkça gizleme seçeneği olarak klavyenin gösterilmesine neden olan alanda bir bulanıklık olayını tetiklememektedir.

ancak yeniden boyutlandırma olayı, klavye herhangi bir nedenle yukarı veya aşağı gelirse bir sihir gibi çalışır.

Kahve:

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

klavye herhangi bir nedenle gösterildiğinde veya gizlendiğinde yanar.

Bununla birlikte, bir android tarayıcı durumunda (uygulama yerine), geri çekildiğinde yeniden boyutlandırmayı tetiklemeyen ancak mevcut pencere boyutunu değiştirmeyen geri çekilebilir bir url çubuğu bulunduğunu unutmayın.


Klavyeyi manuel olarak kapattığınızda tetiklenmeyen bulanıklık olayı için +1. Yeniden boyutlandırma iyi bir fikirdir ve Android cihazlarda iyi sonuç verir.
Ankit Garg

Bunun hem iPhone 5 (iOS 6.0.2) hem de iPad 3 (iOS 6.0) üzerinde çalıştığını doğrulayabilir.
Diego Agulló

1
CrossBrowserTesting'de iOS6'da Chrome 41'de test edildi - yeniden boyutlandırma sanal klavyenin görünmesi veya kaybolması tarafından tetiklenmez.
Dan Dascalescu

4

Klavyeyi algılamak yerine, pencerenin boyutunu algılamaya çalışın

Pencerenin yüksekliği azaltılmışsa ve genişlik hala aynıysa, klavyenin açık olduğu anlamına gelir. Klavye kapalıysa, buna ekleyebilir, herhangi bir giriş alanının odakta olup olmadığını test edebilirsiniz.

Örneğin bu kodu deneyin.

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
Bu artık iOS 8'de çalışmıyor gibi görünüyor. Klavye, içeriğin üzerini kaplıyor ve çoğu durumda içerik, başlangıçta odaklanmış giriş alanlarını gizleyerek aşağı kaydırılıyor.
Rick Strahl

3
pencere yüksekliği, IOS6 penceresinde, iOS 7'den beri klavye dahil yüksekliği döndürür. yükseklik, klavye açıldığında değişir.
Michiel

1
Kaydırma sırasında üst adres çubuğu ekrana girip çıktığında yüksekliğin de değiştiğini unutmayın. Minimum yükseklik değişikliği eklemelisiniz, diyebilirim ki 200px (test edilmemiş).
oriadam

1

Bu çözüm kaydırma konumunu hatırlar

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });

1

Bunu dene:

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

Önceki cevaplarda bir yerde belirtildiği gibi , klavye göründüğünde window.innerHeight değişkeni artık iOS10'da düzgün şekilde güncelleniyor ve önceki sürümler için desteğe ihtiyacım olmadığından, tartışılana göre biraz daha kolay olabilecek aşağıdaki hack ile geldim "çözümler".

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

o zaman kullanabilirsiniz:

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

klavyenin görünür olup olmadığını kontrol etmek için. Bunu bir süredir web uygulamamda kullanıyorum ve iyi çalışıyor, ancak (diğer tüm çözümler gibi) "beklenen" boyut doğru şekilde güncellenmediği için başarısız olduğu bir durumla karşılaşabilirsiniz.


Durumun bu olduğunu umuyordum ama hayır, güncellenmiyor.
Sam Saffron

0

Biraz arama yaptım ve "klavyede gösterilen" veya "klavyede kapatılan" için somut bir şey bulamadım. Desteklenen etkinliklerin resmi listesine bakın . Ayrıca iPad için Teknik Not TN2262'ye bakın. Muhtemelen zaten bildiğiniz gibi, bir vücut olayı varonorientationchange manzara / portreyi algılamak için bağlayabileceğiniz var.

Benzer şekilde, ama çılgın bir tahmin ... yeniden boyutlandırmayı algılamayı denediniz mi? Görüntü alanı değişiklikleri, bu olayı, gösterilen / gizlenen klavyeden dolaylı olarak tetikleyebilir.

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

Bu, herhangi bir yeniden boyutlandırma olayında yeni yüksekliği uyarır ...


10
Ne yazık ki, testlerimde klavye yeniden boyutlandırma olayını tetiklemedi.
LKM

0

Bunu kendim denemedim, bu sadece bir fikir ... ama pencerenin yüksekliğinin ne zaman değiştiğini görmek ve bunun için tasarımı değiştirmek için CSS ile medya sorgularını kullanmayı denediniz mi? Safari mobil'in klavyeyi pencerenin bir parçası olarak tanımadığını hayal ediyorum, bu yüzden umarım işe yarar.

Misal:

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

2
Çok akıllıca bir fikir. Ne yazık ki, testlerimde klavyenin gösterilmesi, medya sorgularını değerlendirmek için kullanılan yükseklik değerlerini etkilemedi.
LKM

Onaylayabilirim: height: 250px benim için çalıştı (en azından Android'de).
WoodrowShigeru

0

Sorun, 2014 yılında bile cihazların ekran yeniden boyutlandırma olaylarını ve ayrıca kaydırma olaylarını, yazılım klavyesi açıkken tutarsız bir şekilde işlemesidir.

Bir bluetooth klavye kullanıyor olsanız bile, özellikle iOS'un bazı garip düzen hatalarını tetiklediğini buldum; bu yüzden bir yazılım klavyesi tespit etmek yerine, çok dar ve dokunmatik ekranı olan cihazları hedeflemem gerekti.

Genişlik algılaması için ortam sorgularını (veya window.matchMedia ) ve dokunma olayı algılaması için Modernizr'i kullanıyorum .


0

Belki de uygulamanızın ayarlarında, kullanıcının 'harici klavye takılı mı?' Seçeneğini değiştirebileceği bir onay kutusu olması daha kolaydır.

Küçük harflerle, kullanıcıya harici klavyelerin şu anda günümüz tarayıcılarında tespit edilemediğini açıklayın.


1
Bunun gibi bir geçiş eklemek, uygulamayı bozmayacak başka bir çözüm olmadıkça kesinlikle kabul edilmemesi gereken son çare. Bu, çalışan bir uygulamanın üretilmesini engelleyen bir şey değildir.
Adam Leggett

-2

Peki, giriş kutularınızın odağa sahip olduğunu tespit edebilirsiniz ve klavyenin yüksekliğini bilirsiniz. Ekranın yönünü almak için CSS de mevcut, bu yüzden onu hackleyebileceğinizi düşünüyorum.

Yine de bir şekilde fiziksel bir klavyenin durumunu ele almak istersiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.