Веб-приложение для iPad: обнаружение виртуальной клавиатуры с помощью JavaScript в Safari? - PullRequest
141 голосов
/ 07 апреля 2010

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

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

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

Ответы [ 17 ]

54 голосов
/ 08 апреля 2010

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

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

31 голосов
/ 19 октября 2013

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

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

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

15 голосов
/ 16 октября 2010

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

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

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

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

});

надеюсь, это поможет. Michele

14 голосов
/ 08 апреля 2010

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

11 голосов
/ 12 июля 2013

Во время события фокуса вы можете прокрутить мимо высоты документа и волшебным образом 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, высота клавиатуры равна 44, что является высотой [предыдущей] [следующей] панели инструментов.

При этом обнаружении наблюдается небольшое мерцание, но, кажется, избежать этого невозможно.

8 голосов
/ 07 июня 2012

Редактировать: документально подтверждено Apple, хотя я не смог заставить его работать: WKWebView Поведение с отображением на клавиатуре : "В iOS 10 объекты WKWebView соответствуют собственному поведению Safari путем обновления их свойства 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 /2242339/veb-prilozhenie-dlya-ipad-obnaruzhenie-virtualnoi-klaviatury-s-pomoschy-javascript-v-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 не должен уменьшать область просмотра; старые браузеры IE не будут работать, Opera не работала, потому что Opera сохраняла фокус на элементе после закрытия клавиатуры.

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

5 голосов
/ 06 сентября 2012

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

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

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

кофе:

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

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

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

3 голосов
/ 10 сентября 2014

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

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

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

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()));
    }   
});     
1 голос
/ 17 апреля 2017

Как отмечалось в предыдущих ответах, где-то переменная 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){ ... }

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

1 голос
/ 28 августа 2014

Попробуйте это:

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`
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...