it-swarm.com.ru

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

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

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

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

137
LKM

Я нашел решение, которое работает, хотя это немного некрасиво. Это также не будет работать в любой ситуации, но это работает для меня. Поскольку я адаптирую размер пользовательского интерфейса к размеру окна 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, и, кажется, работает нормально.

53
LKM

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

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

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

28
Per Quested Aronsson

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

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

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

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

});

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

15
Michele

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

14
ianh

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

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

11
Hafthor

Правка: документально подтверждено 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 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 не должен уменьшать область просмотра; старые IE браузеры не будут работать, Opera не работала, потому что Opera сохраняла фокус на элементе после закрытия клавиатуры.

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

8
robocat

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

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

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

кофе: 

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

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

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

5
user1650613

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

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

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

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
K.A

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

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

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
Nalini Amir

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

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });
1
WebsterDevelopine

В браузере 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
0
Udo

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

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

0
Ian White

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

Пример:

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

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

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

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

0
pixelbandito

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

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

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

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

0
slf