iPad Web App: Detectar teclado virtual usando JavaScript no Safari?

Estou escrevendo um aplicativo da web para o iPad ( não é um aplicativo comum da App Store – é escrito usando HTML, CSS e JavaScript). Como o teclado preenche uma grande parte da canvas, faria sentido alterar o layout do aplicativo para se ajustar ao espaço restante quando o teclado for exibido. No entanto, não encontrei uma maneira de detectar quando ou se o teclado é exibido.

Minha primeira ideia foi assumir que o teclado é visível quando um campo de texto tem foco. No entanto, quando um teclado externo é anexado a um iPad, o teclado virtual não aparece quando um campo de texto recebe foco.

Nos meus experimentos, o teclado também não afetou a altura ou a altura de rolagem de nenhum dos elementos DOM, e não encontrei nenhum evento ou propriedade proprietária que indique se o teclado está visível.

    Eu encontrei uma solução que funciona, embora seja um pouco feia. Também não funciona em todas as situações, mas funciona para mim. Como estou adaptando o tamanho da interface do usuário ao tamanho da janela do iPad, o usuário normalmente não consegue rolar. Em outras palavras, se eu definir o scrollTop da janela, ele permanecerá em 0.

    Se, por outro lado, o teclado é mostrado, a rolagem de repente funciona. Então eu posso definir scrollTop, imediatamente testar seu valor e, em seguida, redefini-lo. Veja como isso pode parecer no 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, você esperaria que isso não fosse visível para o usuário. Infelizmente, pelo menos quando rodando no Simulador, o iPad visivelmente (embora rapidamente) rola para cima e para baixo novamente. Ainda assim, funciona, pelo menos em algumas situações específicas.

    Eu testei isso em um iPad e parece funcionar bem.

    Você pode usar o evento focusout para detectar a dispensa do teclado. É como borrão, mas bolhas. Ele irá triggersr quando o teclado fechar (mas também em outros casos, é claro). No Safari e no Chrome, o evento só pode ser registrado com addEventListener, não com methods legados. Aqui está um exemplo que usei para restaurar um aplicativo Phonegap após a exclusão do teclado.

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

    Sem esse snippet, o contêiner do aplicativo permaneceu na posição de rolagem para cima até a atualização da página.

    talvez uma solução um pouco melhor seja ligar (com jQuery no meu caso) o evento “blur” nos vários campos de input.

    Isso porque quando o teclado desaparece, todos os campos do formulário ficam desfocados. Então, para a minha situação, este recorte resolveu o problema.

     $('input, textarea').bind('blur', function(e) { // Keyboard disappeared window.scrollTo(0, 1); }); 

    espero que ajude. Michele

    Se houver um teclado na canvas, a focalização de um campo de texto próximo à parte inferior da viewport fará com que o Safari role o campo de texto para a visualização. Pode haver alguma maneira de explorar esse fenômeno para detectar a presença do teclado (com um pequeno campo de texto na parte inferior da página que ganha foco momentaneamente, ou algo parecido).

    Durante o evento de foco, você pode rolar além da altura do documento e, magicamente, o window.innerHeight é reduzido pela altura do teclado virtual. Observe que o tamanho do teclado virtual é diferente para as orientações paisagem x retrato, portanto, você precisará redetectá-lo quando for alterado. Aconselho que não se lembre desses valores, pois o usuário pode conectar / desconectar um teclado Bluetooth a qualquer 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; }; 

    Observe que quando o usuário está usando um teclado bluetooth, o keyboardHeight é 44, que é a altura da barra de ferramentas [previous] [next].

    Há um pouco de cintilação quando você faz essa detecção, mas não parece possível evitá-lo.

    Edit: Documentado pela Apple, embora eu não conseguisse fazê-lo funcionar: WKWebView Behavior with Keyboard Displays : “No iOS 10, os objects WKWebView correspondem ao comportamento nativo do Safari, atualizando sua propriedade window.innerHeight quando o teclado é mostrado e não chamam resize events “(talvez seja possível usar focus ou focus plus delay para detectar o teclado em vez de usar o redimensionamento).

    Edit: código presume teclado na canvas, teclado não externo. Deixá-lo porque as informações podem ser úteis para outras pessoas que só se preocupam com os teclados na canvas. Use http://jsbin.com/AbimiQup/4 para visualizar os parâmetros da página.

    Nós testamos para ver se o document.activeElement é um elemento que mostra o teclado (input type = text, textarea, etc).

    O código a seguir falsifica as coisas para nossos propósitos (embora geralmente não esteja correto).

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

    O código acima é apenas aproximado: é errado para o teclado dividido, o teclado desancorado, o teclado físico. Como comentário no topo, você pode ser capaz de fazer um trabalho melhor do que o código fornecido no Safari (desde iOS8?) Ou WKWebView (desde iOS10) usando a propriedade window.innerHeight .

    Eu encontrei falhas em outras circunstâncias: por exemplo, dar foco à input, em seguida, ir para a canvas inicial, em seguida, voltar para a página; O iPad não deve tornar a viewport menor; navegadores antigos do IE não funcionarão, o Opera não funcionou porque o Opera manteve o foco no elemento após o teclado ser fechado.

    No entanto, a resposta marcada (mudança de rolagem para medir a altura) tem desagradáveis ​​efeitos colaterais da interface do usuário se a janela de exibição for zoom (ou força-zoom habilitado nas preferências). Eu não uso a outra solução sugerida (mudança de scrolltop) porque no iOS, quando a viewport é zoom e rolagem para input focada, há interações com bugs entre scrolling & zoom & focus (que podem deixar uma input focada fora da viewport – não visível).

    Apenas testado no Android 4.1.1:

    O evento de desfocagem não é um evento fiável para testar o teclado para cima e para baixo porque o utilizador tem a opção de ocultar explicitamente o teclado, o que não desencadeia um evento de desfocagem no campo que causou a apresentação do teclado.

    No entanto, o evento de redimensionamento funciona como um encanto se o teclado subir ou descer por qualquer motivo.

    café:

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

    triggers sempre que o teclado é mostrado ou oculto por qualquer motivo.

    Note, no entanto, no caso de um navegador android (em vez de app), há uma barra de url retrátil que não triggers resize quando é recolhida ainda altera o tamanho da janela disponível.

    Em vez de detectar o teclado, tente detectar o tamanho da janela

    Se a altura da janela foi reduzida e a largura ainda é a mesma, significa que o teclado está ligado. Se o teclado estiver desligado, você também pode adicionar a isso, testar se algum campo de input está em foco ou não.

    Tente este código por exemplo.

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

    Esta solução lembra a posição de rolagem

      var currentscroll = 0; $('input').bind('focus',function() { currentscroll = $(window).scrollTop(); }); $('input').bind('blur',function() { if(currentscroll != $(window).scrollTop()){ $(window).scrollTop(currentscroll); } }); 

    Tente 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` 

    Eu fiz algumas pesquisas, e não consegui encontrar nada concreto para um “no teclado mostrado” ou “no teclado dispensado”. Veja a lista oficial de events suportados . Veja também a Nota Técnica TN2262 para o iPad. Como você provavelmente já sabe, há um evento onorientationchange você pode conectar para detectar paisagem / retrato.

    Da mesma forma, mas um palpite … você já tentou detectar resize? As mudanças na janela de exibição podem acionar o evento indiretamente a partir do teclado que está sendo mostrado / oculto.

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

    O que simplesmente alertaria a nova altura em qualquer evento de redimensionamento ….

    Eu não tentei isso sozinho, por isso é apenas uma idéia … mas você já tentou usar consultas de mídia com CSS para ver quando a altura da janela muda e, em seguida, alterar o design para isso? Eu imagino que o Safari Mobile não está reconhecendo o teclado como parte da janela, então espero que funcione.

    Exemplo:

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

    O problema é que, mesmo em 2014, os dispositivos manipulam os events de redimensionamento de canvas, bem como os events de rolagem, de forma inconsistente, enquanto o teclado virtual está aberto.

    Descobri que, mesmo se você estiver usando um teclado bluetooth, o iOS em particular triggers alguns bugs de layout estranhos; então, em vez de detectar um teclado virtual, acabei de segmentar dispositivos muito estreitos e com canvass sensíveis ao toque.

    Eu uso media queries (ou window.matchMedia ) para detecção de largura e Modernizr para detecção de events de toque.

    Como observado nas respostas anteriores em algum lugar, a variável window.innerHeight é atualizada corretamente agora no iOS10 quando o teclado aparece e, como não preciso do suporte para versões anteriores, desenvolvi o seguinte hack que pode ser um pouco mais fácil do que o discutido “soluções”.

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

    então você pode usar:

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

    para verificar se o teclado está visível. Eu tenho usado por um tempo agora no meu aplicativo da web e funciona bem, mas (como todas as outras soluções) você pode encontrar uma situação em que ele falha porque o tamanho “esperado” não é atualizado corretamente ou algo assim.

    Talvez seja mais fácil ter uma checkbox de seleção nas configurações do seu aplicativo, onde o usuário pode alternar entre “teclado externo conectado”.

    Em letras pequenas, explique ao usuário que atualmente os teclados externos não são detectáveis ​​nos navegadores atuais.

    Bem, você pode detectar quando suas checkboxs de input têm o foco e você sabe a altura do teclado. Há também CSS disponível para obter a orientação da canvas, então eu acho que você pode hackear.

    Você iria querer lidar com o caso de um teclado físico de alguma forma, no entanto.