Aplicación Web para iPad: ¿Detecta un Teclado Virtual usando JavaScript en Safari?


Estoy escribiendo una aplicación web para el iPad ( no es una aplicación normal de la Tienda de aplicaciones - está escrito usando HTML, CSS y JavaScript). Dado que el teclado llena una gran parte de la pantalla, tendría sentido cambiar el diseño de la aplicación para que se ajuste al espacio restante cuando se muestre el teclado. Sin embargo, no he encontrado ninguna manera de detectar cuándo o si se muestra el teclado.

Mi primera idea fue asumir que el teclado es visible cuando un campo de texto tiene foco. Sin embargo, cuando un teclado externo está conectado a un iPad, el teclado virtual no se muestra cuando un campo de texto recibe enfoque.

En mis experimentos, el teclado tampoco afectó la altura o la altura de desplazamiento de ninguno de los elementos DOM, y no he encontrado eventos o propiedades propietarias que indiquen si el teclado es visible.

Author: LKM, 2010-04-07

16 answers

Encontré una solución que funciona, aunque es un poco fea. Tampoco funcionará en todas las situaciones, pero funciona para mí. Dado que estoy adaptando el tamaño de la interfaz de usuario al tamaño de la ventana del iPad, el usuario normalmente no puede desplazarse. En otras palabras, si establezco el scrollTop de la ventana, permanecerá en 0.

Si, por el contrario, se muestra el teclado, el desplazamiento de repente funciona. Así que puedo configurar scrollTop, probar inmediatamente su valor y luego restablecerlo. Así es como podría verse código, 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, se espera que esto no sea visible para el usuario. Desafortunadamente, al menos cuando se ejecuta en el Simulador, el iPad visiblemente (aunque rápidamente) se desplaza hacia arriba y hacia abajo de nuevo. Aún así, funciona, al menos en algunas situaciones específicas.

He probado esto en un iPad, y parece funcionar bien.

 52
Author: LKM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-21 12:15:45

Puede usar el evento focusout para detectar la salida del teclado. Es como desenfoque, pero burbujas. Se disparará cuando el teclado se cierre (pero también en otros casos, por supuesto). En Safari y Chrome, el evento solo se puede registrar con addEventListener, no con métodos heredados. Aquí hay un ejemplo que utilicé para restaurar una aplicación Phonegap después de la eliminación del teclado.

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

Sin este fragmento, el contenedor de la aplicación permaneció en la posición de desplazamiento ascendente hasta la actualización de la página.

 27
Author: Per Quested Aronsson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-19 08:27:59

Tal vez una solución ligeramente mejor es enlazar (con jQuery en mi caso) el evento "desenfoque" en los diversos campos de entrada.

Esto se debe a que cuando el teclado desaparece todos los campos del formulario están borrosos. Así que para mi situación este corte resolvió el problema.

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

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

});

Espero que ayude. Michele

 15
Author: Michele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-16 17:38:42

Si hay un teclado en pantalla, enfocar un campo de texto que está cerca de la parte inferior de la ventana hará que Safari desplace el campo de texto hasta la vista. Puede haber alguna forma de explotar este fenómeno para detectar la presencia del teclado (tener un pequeño campo de texto en la parte inferior de la página que se enfoca momentáneamente, o algo así).

 14
Author: ianh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-08 09:31:38

Durante el evento focus puede desplazarse más allá de la altura del documento y mágicamente de la ventana.innerHeight se reduce por la altura del teclado virtual. Tenga en cuenta que el tamaño del teclado virtual es diferente para las orientaciones horizontal y vertical, por lo que deberá volver a detectarlo cuando cambie. Desaconsejaría recordar estos valores ya que el usuario podría conectar/desconectar un teclado bluetooth en cualquier 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;
};

Tenga en cuenta que cuando el usuario está utilizando un teclado bluetooth, el keyboardHeight es 44, que es la altura de la barra de herramientas [anterior] [siguiente].

Hay un pequeño parpadeo cuando haces esta detección, pero no parece posible evitarlo.

 11
Author: Hafthor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-15 20:03:07

Editar: Documentado por Apple aunque en realidad no pude conseguir que funcione: WKWebView Comportamiento con Pantallas de teclado: "En iOS 10, los objetos WKWebView coinciden con el comportamiento nativo de Safari al actualizar su ventana.innerHeight propiedad cuando se muestra el teclado, y no llamar a eventos de redimensionamiento " (tal vez puede utilizar enfoque o enfoque más retraso para detectar el teclado en lugar de utilizar redimensionamiento).

Editar: el código presume teclado en pantalla, no teclado externo. Dejándolo porque la información puede ser útil para otros que solo se preocupan por los teclados en pantalla. Use http://jsbin.com/AbimiQup/4 para ver los parámetros de la página.

Probamos para ver si el document.activeElement es un elemento que muestra el teclado (input type=text, textarea, etc).

El siguiente código falsifica las cosas para nuestros propósitos (aunque generalmente no es correcto).

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

El código anterior es solo aproximado: Es incorrecto para teclado dividido, teclado desacoplado, teclado físico. Según el comentario en la parte superior, usted puede ser capaz de hacer un mejor trabajo que el código dado en Safari (desde iOS8?) o WKWebView (desde iOS10) usando la propiedad window.innerHeight.

He encontrado fallos en otras circunstancias: por ejemplo, dar foco a la entrada y luego ir a la pantalla de inicio y luego volver a la página; iPad shouldnt hacer viewport más pequeño; navegadores IE antiguos no funcionará, Opera no funciona porque Opera mantuvo el foco en el elemento después de teclado cerrado.

Sin embargo, la respuesta etiquetada (cambiar scrolltop para medir la altura) tiene efectos secundarios desagradables UI si viewport zoomable (o forzar zoom activado en preferencias). No uso la otra solución sugerida (cambiar scrolltop) porque en iOS, cuando viewport es ampliable y se desplaza a la entrada enfocada, hay interacciones con errores entre el desplazamiento y el zoom y el enfoque (que puede dejar una entrada solo enfocada fuera de viewport - no visible).

 8
Author: robocat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-26 04:15:02

Solo probado en Android 4.1.1:

El evento de desenfoque no es un evento confiable para probar el teclado hacia arriba y hacia abajo porque el usuario como opción para ocultar explícitamente el teclado que no desencadena un evento de desenfoque en el campo que causó que el teclado se muestre.

Sin embargo, el evento Redimensionar funciona como un encanto si el teclado sube o baja por cualquier razón.

Café:

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

Se activa cada vez que se muestra u oculta el teclado por cualquier motivo.

Tenga en cuenta, sin embargo, en el caso de un navegador Android (en lugar de aplicación) hay una barra de url retráctil que no redimensiona el fuego cuando se retrae, pero sí cambia el tamaño de la ventana disponible.

 5
Author: user1650613,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-06 02:08:42

En Lugar de detectar el teclado, intente detectar el tamaño de la ventana

Si la altura de la ventana se redujo, y el ancho sigue siendo el mismo, significa que el teclado está encendido. De lo contrario, el teclado está apagado, también puede agregar a eso, probar si cualquier campo de entrada está enfocado o no.

Pruebe este código, por ejemplo.

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
Author: K.A,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-10 14:41:29

Esta solución recuerda la posición del desplazamiento

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });
 1
Author: WebsterDevelopine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-15 05:07:40

Prueba este:

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
Author: Nalini Amir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-28 09:54:14

Hice algunas búsquedas, y no pude encontrar nada concreto para un "on keyboard shown" o "on keyboard dismissed". Ver la lista oficial de eventos soportados. Ver también Nota técnica TN2262 para iPad. Como probablemente ya sepa, hay un evento corporal onorientationchange que puede conectar para detectar paisaje/retrato.

Del mismo modo, pero una conjetura salvaje... ¿has intentado detectar el cambio de tamaño? Los cambios en la vista pueden desencadenar ese evento indirectamente desde el teclado que se muestra / oculto.

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

Que simplemente alertaría a la nueva altura en cualquier evento de cambio de tamaño....

 0
Author: slf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-08 14:24:04

Yo no he intentado esto, así que es solo una idea... pero, ¿ha intentado usar media queries con CSS para ver cuándo cambia la altura de la ventana y luego cambiar el diseño para eso? Me imagino que Safari Mobile no reconoce el teclado como parte de la ventana, por lo que espero que funcione.

Ejemplo:

@media all and (height: 200px){
    #content {height: 100px; overflow: hidden;}
}
 0
Author: Janae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-05 16:58:45

El problema es que, incluso en 2014, los dispositivos manejan eventos de cambio de tamaño de pantalla, así como eventos de desplazamiento, de manera inconsistente mientras el teclado está abierto.

He encontrado que, incluso si está utilizando un teclado bluetooth, iOS en particular desencadena algunos errores de diseño extraños; así que en lugar de detectar un teclado de software, solo he tenido que apuntar a dispositivos que son muy estrechos y tienen pantallas táctiles.

Uso media queries (o ventana .matchMedia) para la detección de ancho y Modernizr para la detección de eventos táctiles.

 0
Author: pixelbandito,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-07 19:55:53

Como se señaló en las respuestas anteriores en algún lugar de la ventana .La variable innerHeight se actualiza correctamente ahora en iOS10 cuando aparece el teclado y ya que no necesito el soporte para versiones anteriores, se me ocurrió el siguiente truco que podría ser un poco más fácil que las "soluciones"discutidas.

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

Entonces puedes usar:

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

Para comprobar si el teclado está visible. Lo he estado usando desde hace un tiempo en mi aplicación web y funciona bien ,pero (como todas las otras soluciones) es posible que encuentre una situación en la que falla porque el tamaño "esperado" no se actualiza correctamente o algo así.

 0
Author: Flow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-24 09:37:08

Tal vez sea más fácil tener una casilla de verificación en la configuración de su aplicación donde el usuario puede alternar 'teclado externo conectado?'.

En letra pequeña, explique al usuario que los teclados externos no son detectables en los navegadores actuales.

 0
Author: Ian White,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-13 05:43:38

Bueno, puedes detectar cuando tus cajas de entrada tienen el foco, y sabes la altura del teclado. También hay CSS disponible para obtener la orientación de la pantalla, así que creo que puedes hackearlo.

Sin embargo, querrías manejar el caso de un teclado físico de alguna manera.

 -1
Author: stuntmouse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-08 11:16:19