App Web per iPad: Rileva tastiera virtuale usando JavaScript in Safari?


147

Sto scrivendo un'app Web per iPad ( non un'app App Store normale - è scritta utilizzando HTML, CSS e JavaScript). Poiché la tastiera riempie una parte enorme dello schermo, sarebbe logico cambiare il layout dell'app per adattarlo allo spazio rimanente quando viene mostrata la tastiera. Tuttavia, non ho trovato alcun modo per rilevare quando o se viene mostrata la tastiera.

La mia prima idea è stata quella di supporre che la tastiera sia visibile quando un campo di testo è attivo. Tuttavia, quando una tastiera esterna è collegata a un iPad, la tastiera virtuale non viene visualizzata quando un campo di testo viene attivato.

Nei miei esperimenti, anche la tastiera non ha influenzato l'altezza o l'altezza di scorrimento di nessuno degli elementi DOM e non ho trovato eventi o proprietà proprietari che indicano se la tastiera è visibile.


1
Hm, problema interessante. Prova a scorrere gli oggetti "finestra" su Safari di iPad per vedere se ci sono oggetti speciali relativi al supporto della tastiera.
David Murdoch,

@David che non funzionerà, la tastiera non è una "finestra" Javascript.
kennytm,

2
@KennyTM. Duh. Ma potrebbe esserci una bandiera relativa alla visualizzazione della tastiera su schermo in uno qualsiasi degli oggetti della finestra. Vale la pena provare.
David Murdoch,

1
Ci ho provato. Purtroppo non ho trovato nulla. Inoltre, ho confrontato tutte le proprietà della finestra con tre livelli di profondità prima e dopo aver mostrato la tastiera. Nessuna delle differenze sembrava rilevante come indicatori per la tastiera.
LKM,

3
C'è una risposta più recente per questo ??
frana il

Risposte:


54

Ho trovato una soluzione che funziona, anche se è un po 'brutta. Inoltre non funzionerà in ogni situazione, ma funziona per me. Poiché sto adattando le dimensioni dell'interfaccia utente alle dimensioni della finestra dell'iPad, l'utente normalmente non è in grado di scorrere. In altre parole, se imposto lo scrollTop della finestra, rimarrà a 0.

Se, d'altra parte, viene mostrata la tastiera, lo scorrimento improvvisamente funziona. Quindi posso impostare scrollTop, testare immediatamente il suo valore e quindi ripristinarlo. Ecco come potrebbe apparire nel codice, usando 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 ');
    });
});

Normalmente, ti aspetteresti che questo non sia visibile all'utente. Sfortunatamente, almeno quando si esegue nel simulatore, l'iPad scorre visibilmente (anche se rapidamente) su e giù di nuovo. Tuttavia, funziona, almeno in alcune situazioni specifiche.

L'ho provato su un iPad e sembra funzionare bene.


Sto riscontrando un problema con la mia app Web in cui quando l'input è focalizzato, lo schermo si sposta un po 'verso l'alto. Altrimenti ho disabilitato lo scorrimento, ma comunque questo scorre. Qualche idea? Grazie [ stackoverflow.com/questions/6740253/…
Andrew Samuelsen,

Non l'ho ancora provato, ma sembra promettente. Non .scrollTop(1)funzionerebbe altrettanto bene e sarebbe meno ovvio?
ThinkingStiff

1
Questa è una cattiva idea ... La tastiera potrebbe essere bluetooth e virtuale potrebbe non essere visualizzata.
theSociableme,

3
@theSociableme: il punto centrale di questa soluzione è gestire correttamente la tastiera bluetooth. Se hai ignorato le tastiere bluetooth, capire se la tastiera virtuale è stata mostrata sarebbe facile, dal momento che potresti semplicemente verificare se un campo era attivo.
LKM,

5
@fraxture: non conosco una spiegazione esaustiva (se cerchi e ne scrivi una, mi piacerebbe leggerla). Le due piattaforme gestiscono le tastiere su schermo nei loro browser principali in modo molto diverso. Android Chrome riduce l'altezza della finestra per fare spazio alla tastiera, quindi la pagina viene ridimensionata quando viene visualizzata la tastiera. iOS Safari sovrappone la pagina con la tastiera (le dimensioni della pagina rimangono le stesse) e cambia il funzionamento dello scorrimento. Safari fa scorrere la pagina all'interno del viewport e contemporaneamente sposta il viewport, assicurandosi che la parte inferiore della pagina sia sopra la tastiera quando viene fatta scorrere verso il basso.
LKM,

32

È possibile utilizzare l' evento focusout per rilevare l' eliminazione della tastiera. È come sfocatura, ma bolle. Si attiverà alla chiusura della tastiera (ma anche in altri casi, ovviamente). In Safari e Chrome l'evento può essere registrato solo con addEventListener, non con metodi legacy. Ecco un esempio che ho usato per ripristinare un'app Phonegap dopo il licenziamento della tastiera.

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

Senza questo frammento, il contenitore dell'app è rimasto nella posizione di scorrimento verso l'alto fino all'aggiornamento della pagina.


1
miglior soluzione che ho trovato per il mio problema
Sutulustus,


1
Inoltre puoi usare la versione 'focusin' per rilevare la tastiera aperta.
A.Çetin,

15

forse una soluzione leggermente migliore è quella di associare (con jQuery nel mio caso) l'evento "sfocatura" sui vari campi di input.

Questo perché quando la tastiera scompare tutti i campi del modulo sono sfocati. Quindi per la mia situazione questo frammento ha risolto il problema.

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

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

});

spero che sia d'aiuto. Michele


Grazie per questa risposta Ho trovato utile risolvere un problema in cui la tastiera Safari di iPad causava lo spostamento (offset) del cursore textarea all'esterno dell'area textarea.
kennbrodhagen,

14

Se è presente una tastiera su schermo, la messa a fuoco di un campo di testo vicino alla parte inferiore del riquadro di visualizzazione farà scorrere il campo di testo in vista. Potrebbe esserci un modo per sfruttare questo fenomeno per rilevare la presenza della tastiera (con un minuscolo campo di testo nella parte inferiore della pagina che ottiene momentaneamente la messa a fuoco, o qualcosa del genere).


1
È un'idea geniale. Ho trovato una soluzione simile che utilizza anche la posizione di scorrimento corrente per rilevare la tastiera virtuale.
LKM

geniale! mi hai salvato la giornata!
Aztack

11

Durante l'evento focus è possibile scorrere oltre l'altezza del documento e magicamente la finestra.innerHeight è ridotto dall'altezza della tastiera virtuale. Tieni presente che la dimensione della tastiera virtuale è diversa per gli orientamenti orizzontale e verticale, quindi dovrai rileggerla quando cambia. Vorrei sconsigliare di ricordare questi valori poiché l'utente potrebbe collegare / disconnettere una tastiera bluetooth in qualsiasi momento.

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

Si noti che quando l'utente utilizza una tastiera bluetooth, la tastiera Altezza è 44 che è l'altezza della barra degli strumenti [precedente] [successiva].

C'è un piccolo sfarfallio quando si fa questo rilevamento, ma non sembra possibile evitarlo.


5
Ho appena provato questo in iOS 8.2 e non funziona ... ha smesso di funzionare ad un certo punto per il nuovo iOS?
Ming,

1
Non ha funzionato neanche per me - il ridimensionamento non viene attivato in iOS9.3
llamerr

8

Modifica: documentato da Apple, anche se in realtà non sono riuscito a farlo funzionare: comportamento di WKWebView con display a tastiera : "In iOS 10, gli oggetti WKWebView corrispondono al comportamento nativo di Safari aggiornando la proprietà window.innerHeight quando viene mostrata la tastiera e non chiamano eventi di ridimensionamento "(forse è possibile utilizzare lo stato attivo o attivo più il ritardo per rilevare la tastiera anziché utilizzare il ridimensionamento).

Modifica: il codice presume la tastiera su schermo, non quella esterna. Lasciandolo perché le informazioni possono essere utili ad altri che si preoccupano solo delle tastiere su schermo. Utilizzare http://jsbin.com/AbimiQup/4 per visualizzare i parametri della pagina.

Testiamo per vedere se document.activeElementè un elemento che mostra la tastiera (tipo di input = testo, textarea, ecc.).

Il codice seguente confonde le cose per i nostri scopi (sebbene non sia generalmente corretto).

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

Il codice sopra è solo approssimativo: è sbagliato per tastiera divisa, tastiera sganciata, tastiera fisica. Come da commento in alto, potresti essere in grado di fare un lavoro migliore rispetto al codice dato su Safari (da iOS8?) O WKWebView (da iOS10) usando la window.innerHeightproprietà.

Ho riscontrato guasti in altre circostanze: ad es. Concentrarsi sull'input, quindi tornare alla schermata principale e tornare alla pagina; iPad non dovrebbe ridurre le dimensioni del viewport; i vecchi browser IE non funzionavano, Opera non funzionava perché Opera si concentrava sull'elemento dopo la chiusura della tastiera.

Tuttavia, la risposta con tag (modifica del riquadro di scorrimento per misurare l'altezza) ha effetti collaterali UI cattivi se il viewport è zoomabile (o lo zoom forzato abilitato nelle preferenze). Non utilizzo l'altra soluzione suggerita (modifica del riquadro di scorrimento) perché su iOS, quando il viewport è zoomabile e scorre verso l'input focalizzato, ci sono interazioni errate tra scorrimento e zoom e focus (che possono lasciare un input focalizzato al di fuori del viewport - no visibile).


A seconda del browser innerHeight per rilevare interruzioni a schermo intero quando alcuni elementi sono posizionati in modo assoluto. Per nulla affidabile.
Udo,

5

Testato solo su Android 4.1.1:

L'evento di sfocatura non è un evento affidabile per testare la tastiera su e giù perché l'utente come opzione per nascondere esplicitamente la tastiera che non attiva un evento di sfocatura sul campo che ha causato la visualizzazione della tastiera.

l'evento di ridimensionamento tuttavia funziona come un incantesimo se la tastiera si alza o si abbassa per qualsiasi motivo.

caffè:

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

si attiva ogni volta che la tastiera viene mostrata o nascosta per qualsiasi motivo.

Si noti tuttavia che nel caso di un browser Android (anziché di un'app) è presente una barra dell'URL a scomparsa che non attiva il ridimensionamento quando viene ritratta ma cambia la dimensione della finestra disponibile.


+1 per l'evento di sfocatura non attivato quando si elimina manualmente la tastiera. Il ridimensionamento è una buona idea e funzionerebbe bene per i dispositivi Android.
Ankit Garg,

Può confermare che funziona sia su iPhone 5 (iOS 6.0.2) che su iPad 3 (iOS 6.0).
Diego Agulló,

1
Appena testato su Chrome 41 su iOS6 su CrossBrowserTesting - il ridimensionamento non è attivato dalla tastiera virtuale che appare o scompare.
Dan Dascalescu,

4

Invece di rilevare la tastiera, prova a rilevare la dimensione della finestra

Se l'altezza della finestra è stata ridotta e la larghezza è sempre la stessa, significa che la tastiera è attiva. Altrimenti la tastiera è spenta, puoi anche aggiungere a quella, verificare se qualche campo di input è attivo o meno.

Prova questo codice per esempio.

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
Ciò non sembra funzionare più in iOS 8. La tastiera sovrappone il contenuto e in molti casi il contenuto scorre verso il basso oscurando i campi di input inizialmente focalizzati.
Rick Strahl,

3
l'altezza della finestra restituisce l'altezza inclusa la tastiera da iOS 7, in IOS6 window.height cambia quando si apre la tastiera.
Michiel,

1
Si noti che l'altezza cambia anche quando la barra degli indirizzi superiore scorre dentro e fuori dallo schermo durante lo scorrimento. Dovresti aggiungere un minimo cambiamento di altezza di, direi, 200 px (non testato).
Oriadam,

1

Questa soluzione ricorda la posizione di scorrimento

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });

1

Prova questo:

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

Come notato nelle risposte precedenti da qualche parte, la variabile window.innerHeight viene aggiornata correttamente ora su iOS10 quando appare la tastiera e poiché non ho bisogno del supporto per le versioni precedenti, ho trovato il seguente hack che potrebbe essere un po 'più facile di quello discusso "soluzioni".

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

allora puoi usare:

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

per verificare se la tastiera è visibile. Lo sto usando da un po 'di tempo nella mia app Web e funziona bene, ma (come tutte le altre soluzioni) potresti trovare una situazione in cui fallisce perché la dimensione "prevista" non viene aggiornata correttamente o qualcosa del genere.


Speravo che fosse così, ma no, non viene aggiornato.
Sam Saffron,

0

Ho fatto qualche ricerca e non sono riuscito a trovare nulla di concreto per un "sulla tastiera mostrato" o "sulla tastiera scartato". Vedi l'elenco ufficiale degli eventi supportati . Vedi anche la nota tecnica TN2262 per iPad. Come probabilmente già saprai, c'è un evento corporeo onorientationchangeche puoi collegare per rilevare il paesaggio / ritratto.

Allo stesso modo, ma un'ipotesi selvaggia ... hai provato a rilevare il ridimensionamento? Le modifiche alla vista possono attivare quell'evento indirettamente dalla tastiera mostrata / nascosta.

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

Che avviserebbe semplicemente la nuova altezza su qualsiasi evento di ridimensionamento ....


10
Sfortunatamente, nei miei test, la tastiera non ha attivato l'evento di ridimensionamento.
LKM,

0

Non ho provato questo da solo, quindi è solo un'idea ... ma hai provato a utilizzare le media query con CSS per vedere quando l'altezza della finestra cambia e quindi cambiare il design per quello? Immagino che Safari mobile non riconosca la tastiera come parte della finestra, quindi si spera che funzioni.

Esempio:

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

2
Un'idea molto intelligente. Sfortunatamente, nei miei test, mostrare la tastiera non ha influito sui valori di altezza utilizzati per valutare le query multimediali.
LKM,

Posso confermare: altezza: 250 px ha funzionato per me (almeno su Android).
Woodrow Shigeru,

0

Il problema è che, anche nel 2014, i dispositivi gestiscono gli eventi di ridimensionamento dello schermo, nonché gli eventi di scorrimento, in modo incoerente mentre la tastiera software è aperta.

Ho scoperto che, anche se stai usando una tastiera bluetooth, iOS in particolare attiva alcuni strani bug di layout; quindi, invece di rilevare una tastiera software, ho dovuto scegliere come target dispositivi molto stretti e dotati di touchscreen.

Uso le media query (o window.matchMedia ) per il rilevamento della larghezza e Modernizr per il rilevamento di eventi touch.


0

Forse è più facile avere una casella di controllo nelle impostazioni della tua app in cui l'utente può attivare "tastiera esterna collegata"?

In caratteri piccoli, spiega all'utente che al momento non sono rilevabili tastiere esterne nei browser di oggi.


1
L'aggiunta di un interruttore come questo è l'ultima risorsa che non dovrebbe essere considerata accettabile affatto a meno che non ci sia altra soluzione che non rompa l'app. Questo non è qualcosa che dovrebbe essere un blocco per la produzione di un'app funzionante.
Adam Leggett,

-2

Bene, puoi rilevare quando le caselle di input hanno lo stato attivo e conosci l'altezza della tastiera. Sono disponibili anche CSS per ottenere l'orientamento dello schermo, quindi penso che tu possa hackerarlo.

Tuttavia, in qualche modo vorresti gestire il caso di una tastiera fisica.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.