IPad Web App: обнаружение виртуальной клавиатуры с использованием JavaScript в Safari?

Я пишу веб-приложение для iPad (не обычное приложение App Store), написанное с использованием HTML, CSS и JavaScript). Поскольку клавиатура заполняет огромную часть экрана, имеет смысл изменить макет приложения, чтобы он соответствовал оставшемуся пространству при отображении клавиатуры. Однако я не нашел способа определить, когда или показана клавиатура.

Моя первая идея состояла в том, чтобы предположить, что клавиатура видна, когда текстовое поле имеет фокус. Однако, когда внешняя клавиатура прикреплена к iPad, виртуальная клавиатура не появляется, когда текстовое поле получает фокус.

В моих экспериментах клавиатура также не влияла на высоту или прокрутку любого из элементов DOM, и я не обнаружил никаких проприетарных событий или свойств, которые указывают, видима ли клавиатура.

Ответ 1

Я нашел решение, которое работает, хотя оно немного уродливо. Он также не будет работать в любой ситуации, но он работает для меня. Поскольку я адаптирую размер пользовательского интерфейса к размеру окна iPad, пользователь обычно не может прокручивать. Другими словами, если я устанавливаю окно scrollTop, оно останется равным 0.

Если, с другой стороны, отображается клавиатура, внезапно прокручивается прокрутка. Поэтому я могу установить scrollTop, сразу проверить его значение, а затем reset его. Вот как это могло выглядеть в коде, используя 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 ');
    });
});

Обычно вы ожидаете, что это не будет видно пользователю. К сожалению, по крайней мере, при работе в симуляторе iPad заметно (хотя и быстро) прокручивается вверх и вниз. Тем не менее, он работает, по крайней мере, в некоторых конкретных ситуациях.

Я тестировал это на iPad, и, похоже, он работает нормально.

Ответ 2

Вы можете использовать событие фокуса, чтобы обнаружить отключение клавиатуры. Это как размытие, но пузыри. Он срабатывает, когда клавиатура закрывается (но также и в других случаях, конечно). В Safari и Chrome событие может быть зарегистрировано только с помощью addEventListener, а не с унаследованными методами. Вот пример, который я использовал для восстановления приложения Phonegap после увольнения с клавиатуры.

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

Без этого фрагмента контейнер приложения оставался в прокрученной позиции до обновления страницы.

Ответ 3

может быть, немного лучшее решение - связать (с jQuery в моем случае) событие "размытия" в разных полях ввода.

Это потому, что, когда клавиатура исчезает, все поля формы размыты. Таким образом, для моей ситуации это отрезало проблему.

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

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

});

надеюсь, что это поможет. Мишель

Ответ 4

Если есть экранная клавиатура, фокусировка текстового поля, расположенного в нижней части окна просмотра, заставит Safari прокручивать текстовое поле в виде. Возможно, есть какой-то способ использовать это явление для обнаружения присутствия клавиатуры (с маленьким текстовым полем в нижней части страницы, которое мгновенно набирает фокус или что-то в этом роде).

Ответ 5

Во время фокусного события вы можете прокручивать страницу за высоту документа и, как ни странно, window.innerHeight уменьшается на высоту виртуальной клавиатуры. Обратите внимание, что размер виртуальной клавиатуры отличается от ориентации пейзажа и портретной ориентации, поэтому вам нужно будет ее переделать, когда она изменится. Я бы посоветовал не помнить эти значения, поскольку пользователь мог в любой момент подключить/отключить клавиатуру Bluetooth.

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

Обратите внимание, что когда пользователь использует клавиатуру bluetooth, клавиатураHeight равна 44, которая является высотой панели [предыдущая] [следующая].

Когда вы делаете это обнаружение, есть мельчайшая битка, но избежать этого не представляется возможным.

Ответ 6

Изменить: Документировано Apple, хотя я не мог заставить его работать: WKWebView Поведение с дисплеями клавиатуры: "В iOS 10, Объекты WKWebView соответствуют собственному поведению Safaris, обновляя свойство window.innerHeight, когда клавиатура отображается, и не вызывают события изменения размера" (возможно, вы можете использовать фокус или фокус плюс задержка для обнаружения клавиатуры вместо изменения размера).

Изменить: код предполагает использование экранной клавиатуры, а не внешней клавиатуры. Оставляя это, потому что информация может быть полезной для других, которые заботятся только о экранных клавиатурах. Используйте http://jsbin.com/AbimiQup/4, чтобы просмотреть параметры страницы.

Мы проверяем, является ли document.activeElement элементом, который показывает клавиатуру (тип ввода = текст, текстовое поле и т.д.).

Следующий код подталкивает вещи для наших целей (хотя обычно это не так).

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

Приведенный выше код является приблизительным: он неправильный для разделенной клавиатуры, отстыкованной клавиатуры, физической клавиатуры. В соответствии с комментарием сверху, вы можете сделать лучшую работу, чем данный код в Safari (начиная с iOS8?) Или WKWebView (начиная с iOS10), используя свойство window.innerHeight.

Я обнаружил ошибки при других обстоятельствах: например, дайте фокус на ввод, затем перейдите на главный экран, затем вернитесь на страницу; iPad не должен делать viewport меньше; старые браузеры IE не будут работать, Opera не работает, потому что Opera сосредоточилась на элементе после закрытия клавиатуры.

Однако отмеченный ответ (изменение scrolltop для измерения высоты) имеет неприятные побочные эффекты UI, если масштабирование в viewport (или принудительное увеличение включено в настройках). Я не использую другое предлагаемое решение (изменение scrolltop), потому что на iOS, когда viewport масштабируется и прокручивается на сфокусированный вход, происходят искаженные взаимодействия между прокруткой и масштабированием и фокусировкой (что может оставить только сфокусированный вход вне области просмотра - не виден).

Ответ 7

Проверено только на Android 4.1.1:

blur event не является надежным событием для проверки клавиатуры вверх и вниз, потому что пользователь как опция явно скрывает клавиатуру, которая не вызывает событие размытия в поле, которое вызывало отображение клавиатуры.

изменить размер, однако работает как шарм, если клавиатура подходит по любой причине.

кофе:

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

срабатывает в любое время, когда клавиатура отображается или скрывается по любой причине.

Обратите внимание, однако, что в случае браузера android (а не приложения) есть убирающаяся строка url, которая не снимает размер при отводе, но изменяет размер доступного окна.

Ответ 8

Вместо того, чтобы обнаруживать клавиатуру, попробуйте определить размер окна

Если высота окна была уменьшена, а ширина осталась прежней, это означает, что клавиатура включена. Если клавиатура выключена, вы также можете добавить к ней, проверьте, включено ли какое-либо поле ввода или нет.

Попробуйте этот код, например.

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

Ответ 9

Это решение запоминает положение прокрутки

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });

Ответ 10

Попробуйте следующее:

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`

Ответ 11

Как было отмечено в предыдущих ответах, где-то переменная window.innerHeight теперь обновляется правильно на iOS10, когда появляется клавиатура, и поскольку мне не нужна поддержка более ранних версий, я придумал следующее взломать это может быть немного легче, чем обсуждаемые "решения".

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

то вы можете использовать:

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

чтобы проверить, видима ли клавиатура. Я использую его некоторое время в своем веб-приложении, и он работает хорошо, но (как и все другие решения) вы можете найти ситуацию, когда он терпит неудачу, потому что "ожидаемый" размер не обновляется должным образом или что-то в этом роде.

Ответ 12

Я не пытаюсь это сделать сам, так что это просто идея... но вы пытались использовать медиа-запросы с CSS, чтобы увидеть, когда изменяется высота окна, а затем изменить дизайн для этого? Я бы предположил, что Safari mobile не распознает клавиатуру как часть окна, так что, надеюсь, будет работать.

Пример:

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

Ответ 13

Я сделал некоторые поиски, и я не мог найти ничего конкретного для "показанной клавиатуры" или "на клавиатуре". См. официальный список поддерживаемых событий. Также см. Техническая нота TN2262 для iPad. Как вы, наверное, уже знаете, есть событие body onorientationchange, вы можете подключиться к обнаружению пейзажа/портрета.

Точно так же, но дикая догадка... вы пытались определить размер? Изменения в видовом экране могут инициировать это событие косвенно с отображаемой/скрытой клавиатуры.

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

Что бы просто предупредило новую высоту о любом событии изменения размера.

Ответ 14

Проблема в том, что даже в 2014 году устройства обрабатывают события изменения размера экрана, а также события прокрутки, непостоянно, пока открыта мягкая клавиатура.

Я обнаружил, что даже если вы используете клавиатуру bluetooth, iOS, в частности, вызывает некоторые странные ошибки компоновки; поэтому вместо того, чтобы обнаруживать мягкую клавиатуру, мне просто нужно было настроить таргетинг на устройства, которые очень узкие и имеют сенсорные экраны.

Я использую медиа-запросы (или window.matchMedia) для определения ширины и Modernizr для обнаружения событий касания.

Ответ 15

Возможно, вам проще установить флажок в настройках вашего приложения, где пользователь может переключать "внешнюю клавиатуру?".

В небольшой печати объясните пользователю, что внешние клавиатуры в настоящее время не обнаруживаются в современных браузерах.

Ответ 16

В браузере Safari, когда элемент расположен внизу экрана, а виртуальная клавиатура видна, эта позиция увеличивается примерно на 1 пиксель. Вы можете использовать это.

Предположим, это мобильное устройство в ландшафтном режиме

<div id="detector" style="position: absolute; bottom: 0"></div>

const detector = document.querySelector('#detector');
detector.getBoundingClientRect().bottom // 320

// when virtual keyboard is visible
detector.getBoundingClientRect().bottom // 329 or 328

Ответ 17

Ответ на этот вопрос за 2019 год.

На iOS 12 я не вижу изменения window.innerHeight в зависимости от того, отображается ли клавиатура. Это согласуется с нативным поведением WKWebView, которое просто выталкивает часть экрана за пределы экрана, а не изменяет его размер (что я считаю поведением Android).

Единственный способ добиться успеха - создать элемент фиксированной позиции и проверить его позицию. Элемент должен быть создан за некоторое время до проверки позиции; как правило, создавая его один раз при загрузке и выполняя проверку позже.

var testElement = document.createElement('p');
testElement.style.position = 'fixed';

function isKeyboardVisible() {
  testElement.style.top = 0;
  return !!testElement.offsetTop;
}

setTimeout(function() {
  document.write(isKeyboardVisible() ?
    'Keyboard is visible' :
    'Keyboard is not visisble');
}, 1000);
<input type="text">

Ответ 18

Ну, вы можете обнаружить, когда ваши поля ввода имеют фокус, и вы знаете высоту клавиатуры. Существует также CSS, позволяющий получить ориентацию экрана, поэтому я думаю, что вы можете его взломать.

Однако вы бы хотели обработать случай с физической клавиатурой.