que - Aplicación web iPad: ¿Detecta el teclado virtual usando JavaScript en Safari?
safari no funciona (16)
Bueno, puedes detectar cuándo tus cuadros 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 hackearla.
Sin embargo, querría manejar el caso de un teclado físico de alguna manera.
Estoy escribiendo una aplicación web para el iPad ( no es una aplicación de la tienda de aplicaciones habitual, está escrita con HTML, CSS y JavaScript). Dado que el teclado ocupa 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 muestra el teclado. Sin embargo, no he encontrado manera de detectar cuándo o si se muestra el teclado.
Mi primera idea fue suponer que el teclado está visible cuando un campo de texto tiene foco. Sin embargo, cuando se conecta un teclado externo a un iPad, el teclado virtual no aparece cuando un campo de texto recibe el foco.
En mis experimentos, el teclado tampoco afectó la altura o altura de desplazamiento de ninguno de los elementos DOM, y no he encontrado eventos o propiedades que indiquen si el teclado está visible.
Como se señaló en las respuestas anteriores en algún lugar, la variable window.innerHeight se actualiza correctamente ahora en iOS10 cuando aparece el teclado y como no necesito el soporte para versiones anteriores, se me ocurrió el siguiente truco que podría ser un poco más fácil que el discutido "soluciones".
//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 verificar si el teclado está visible. Lo he estado utilizando durante un tiempo en mi aplicación web y funciona bien, pero (como todas las demás soluciones) es posible que encuentre una situación en la que falla porque el tamaño "esperado" no se actualiza correctamente o algo así.
Durante el evento de enfoque puede desplazarse más allá de la altura del documento y mágicamente la ventana. La altura se reduce por la altura del teclado virtual. Tenga en cuenta que el tamaño del teclado virtual es diferente para las orientaciones de paisaje y retrato, por lo que deberá volver a detectarlo cuando cambie. Aconsejaría no 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 usa un teclado bluetooth, el teclado Height es 44, que es el alto de la barra de herramientas [anterior] [siguiente].
Hay un pequeño parpadeo cuando haces esta detección, pero no parece posible evitarla.
Editar: Documentado por Apple, aunque no pude hacerlo funcionar: WKWebView Behavior with Keyboard Displays : "En iOS 10, los objetos WKWebView coinciden con el comportamiento nativo de Safari actualizando su propiedad window.innerHeight cuando se muestra el teclado, y no llaman cambiar el tamaño de los eventos "(quizás se puede usar el enfoque o el enfoque más la demora para detectar el teclado en lugar de usar el tamaño).
Editar: el código presume el teclado en pantalla, no el teclado externo. Dejarlo 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 document.activeElement
es un elemento que muestra el teclado (tipo de entrada = texto, área de texto, etc.).
El siguiente código modifica 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://.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. Como se comenta en la parte superior, es posible que puedas hacer un mejor trabajo que el código dado en Safari (desde iOS8?) O WKWebView (desde iOS10) usando la propiedad window.innerHeight
.
He encontrado fallas en otras circunstancias: por ejemplo, dar enfoque a la entrada, luego ir a la pantalla de inicio y luego volver a la página; iPad no debería hacer que la ventana gráfica sea más pequeña; los viejos navegadores IE no funcionarán, Opera no funcionó porque Opera mantuvo el foco en el elemento después de que el teclado se cerró.
Sin embargo, la respuesta etiquetada (cambio de desplazamiento para medir la altura) tiene efectos secundarios desagradables en la interfaz de usuario si la vista se puede ampliar (o se puede activar el zoom en las preferencias). No utilizo la otra solución sugerida (cambio scrolltop) porque en iOS, cuando la ventana gráfica es ampliable y se desplaza a la entrada enfocada, hay interacciones erróneas entre desplazamiento y zoom & focus (que pueden dejar una entrada enfocada solo fuera de la ventana gráfica, no visible).
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 incoherente mientras el teclado virtual está abierto.
Descubrí que, incluso si usa un teclado bluetooth, iOS, en particular, desencadena algunos extraños errores de diseño; así que en lugar de detectar un teclado suave, solo tuve que apuntar a dispositivos que son muy estrechos y tienen pantallas táctiles.
Uso las consultas de medios (o window.matchMedia ) para la detección de ancho y Modernizr para la detección de eventos táctiles.
En lugar de detectar el teclado, intente detectar el tamaño de la ventana
Si se redujo la altura de la ventana 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 algún 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()));
}
});
Encontré una solución que funciona, aunque es un poco fea. Tampoco funcionará en todas las situaciones, pero funciona para mí. Como 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 configuro el scrollTop de la ventana, permanecerá en 0.
Si, por otro lado, se muestra el teclado, el desplazamiento funciona de repente. Así que puedo configurar scrollTop, probar su valor inmediatamente y luego reiniciarlo. Así es como podría verse en el 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, esperaría que esto no sea visible para el usuario. Desafortunadamente, al menos cuando se ejecuta en el simulador, el iPad se desplaza visiblemente (aunque rápidamente) hacia arriba y hacia abajo. Aún así, funciona, al menos en algunas situaciones específicas.
He probado esto en un iPad, y parece funcionar bien.
Esta solución recuerda la posición de desplazamiento
var currentscroll = 0;
$(''input'').bind(''focus'',function() {
currentscroll = $(window).scrollTop();
});
$(''input'').bind(''blur'',function() {
if(currentscroll != $(window).scrollTop()){
$(window).scrollTop(currentscroll);
}
});
Hice algunas búsquedas, y no pude encontrar nada concreto para un "teclado mostrado" o "en el teclado descartado". Ver la lista oficial de eventos compatibles . Consulte también la Nota técnica TN2262 para iPad. Como probablemente ya sepa, hay un evento de onorientationchange
cuerpo que puede cablear para detectar paisaje / retrato.
Del mismo modo, pero supongo ... ¿has intentado detectar el cambio de tamaño? Los cambios en la ventana gráfica pueden desencadenar ese evento indirectamente desde el teclado que se muestra / oculta.
window.addEventListener(''resize'', function() { alert(window.innerHeight); });
Lo cual simplemente alertaría la nueva altura en cualquier evento de cambio de tamaño ....
No lo he intentado solo, así que es solo una idea ... pero ¿has intentado utilizar las consultas de medios con CSS para ver cuándo cambia el alto de la ventana y luego cambiar el diseño para eso? Me imagino que el móvil de Safari no reconoce el teclado como parte de la ventana, así que con suerte funcionaría.
Ejemplo:
@media all and (height: 200px){
#content {height: 100px; overflow: hidden;}
}
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`
Puede usar el evento de enfoque para detectar el despido del teclado. Es como borroso, 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 del despido del teclado.
document.addEventListener(''focusout'', function(e) {window.scrollTo(0, 0)});
Sin este fragmento, el contenedor de la aplicación se mantuvo en la posición desplazada hasta la actualización de la página.
Si hay un teclado en pantalla, al enfocar un campo de texto que está cerca de la parte inferior de la ventana gráfica, Safari desplazará el campo de texto a 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 gana foco momentáneamente, o algo así).
Solo probado en Android 4.1.1:
desenfoque evento no es un evento confiable para probar el teclado hacia arriba y hacia abajo porque el usuario como la opción de ocultar explícitamente el teclado que no desencadena un evento de desenfoque en el campo que hizo que el teclado se muestre.
Sin embargo, el cambio de tamaño del evento funciona como un amuleto si el teclado sube o baja por algún motivo.
café:
$(window).bind "resize", (event) -> alert "resize"
dispara en cualquier momento que el teclado se muestra u oculta por alguna razón.
Sin embargo, tenga en cuenta que, en el caso de un navegador de Android (en lugar de una aplicación), hay una barra de URL retráctil que no dispara el cambio de tamaño cuando se retrae pero sí cambia el tamaño de la ventana disponible.
Tal vez es 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 actualmente no son detectables en los navegadores actuales.
tal vez una solución un poco mejor es unir (con jQuery en mi caso) el evento "desenfoque" en los diversos campos de entrada.
Esto porque cuando el teclado desaparece, todos los campos del formulario están borrosos. Entonces, para mi situación, este recorte resolvió el problema.
$(''input, textarea'').bind(''blur'', function(e) {
// Keyboard disappeared
window.scrollTo(0, 1);
});
Espero eso ayude. Michele