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


147

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

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

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


1
Хм, интересная проблема. Попробуйте перебрать объекты «окна» в iPad Safari, чтобы увидеть, есть ли какие-либо специальные объекты, связанные с поддержкой клавиатуры.
Дэвид Мердок

@ Давид, который не будет работать, клавиатура не является «окном» Javascript.
Kennytm

2
@KennyTM. Duh. Но может быть флаг, связанный с отображением экранной клавиатуры в любом из объектов окна. Это стоит выстрел.
Дэвид Мердок

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

3
Есть ли более новый ответ на это ??
Фрагмент

Ответы:


54

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


У меня возникла проблема с моим веб-приложением, когда, когда ввод фокусируется, экран немного прокручивается. В противном случае я отключил прокрутку, но все же это прокрутка. Любые идеи? Спасибо [ stackoverflow.com/questions/6740253/…
Эндрю Самуэльсен

Я еще не пробовал, но выглядит многообещающе. Разве не будет .scrollTop(1)работать так же хорошо и быть менее очевидным?
ThinkingStiff

1
Это плохая идея ... Клавиатура может быть bluetooth, а виртуальная может не отображаться.
theSociableme

3
@theSociableme: весь смысл этого решения состоит в том, чтобы правильно обращаться с клавиатурой Bluetooth. Если вы игнорируете bluetooth-клавиатуры, выяснить, отображается ли виртуальная клавиатура, будет легко, поскольку вы можете просто проверить, было ли поле сфокусировано.
LKM

5
@fraxture: Не знаю подробного объяснения (если вы исследуете и пишете, я бы с удовольствием его прочитал). Две платформы по-разному обрабатывают экранные клавиатуры в своих основных браузерах. Android Chrome уменьшает высоту области просмотра, чтобы освободить место для клавиатуры, поэтому при отображении клавиатуры размер страницы изменяется. iOS Safari накладывает страницу на клавиатуру (размер страницы остается прежним) и меняет способ прокрутки. Safari прокручивает страницу внутри окна просмотра и одновременно перемещает окно просмотра, обеспечивая нижнюю часть страницы над клавиатурой при прокрутке вниз.
LKM

32

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

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

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


1
лучшее решение, которое я нашел для моей проблемы
Sutulustus


1
Также вы можете использовать «фокусирующую» версию для обнаружения открытой клавиатуры.
Четин

15

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

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

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

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

});

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


Спасибо за этот ответ. Я нашел полезным решить проблему, когда клавиатура iPad Safari приводила к смещению (смещению) курсора текстовой области за пределы текстовой области.
Кеннбродхаген

14

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


1
Это гениальная идея. Я нашел похожее решение, которое также использует текущую позицию прокрутки для обнаружения виртуальной клавиатуры.
LKM

молодец! ты спас мой день!
ацтак

11

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

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


5
Я только что попробовал это в iOS 8.2, и это не работает ... перестало ли это работать на каком-то этапе для новой iOS?
Минг

1
У меня тоже не сработало - изменение размера не происходит в iOS9.3
llamerr

8

Изменить: Документация 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, когда область просмотра масштабируется и прокручивается до сфокусированного ввода, между прокруткой, масштабированием и фокусировкой возникают ошибочные взаимодействия (которые могут оставить только сфокусированный ввод за пределами области просмотра - не виден).


В зависимости от браузеров innerHeight позволяет обнаруживать полноэкранные разрывы, когда некоторые элементы располагаются абсолютно. Ненадежный вообще.
Удо

5

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

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

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

кофе:

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

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

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


+1 для события размытия, которое не срабатывает при ручном отключении клавиатуры. Изменение размера это хорошая идея, и она будет хорошо работать на устройствах Android.
Анкит Гарг

Можно подтвердить, что это работает как на iPhone 5 (iOS 6.0.2), так и на iPad 3 (iOS 6.0).
Диего Агулло

1
Только что протестировано на Chrome 41 на iOS6 на CrossBrowserTesting - изменение размера не инициируется появлением или исчезновением виртуальной клавиатуры.
Дан Даскалеску

4

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

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

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

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

2
Похоже, что это больше не работает в iOS 8. Клавиатура накладывает контент, и во многих случаях контент прокручивается вниз, скрывая изначально сфокусированные поля ввода.
Рик Штраль

3
высота окна возвращает высоту, включая клавиатуру, начиная с iOS 7, в окне IOS6. Высота изменяется при открытии клавиатуры.
Михель

1
Обратите внимание, что высота также изменяется, когда верхняя адресная строка скользит по экрану при прокрутке. Вы должны добавить минимальное изменение высоты, я бы сказал, 200px (не проверено).
Ориадам

1

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

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });

1

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

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

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

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


Я надеялся, что это так, но нет, он не обновляется.
Сэм Шафран

0

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

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

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

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


10
К сожалению, в моих тестах клавиатура не вызывала событие изменения размера.
LKM

0

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

Пример:

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

2
Очень умная идея. К сожалению, в моих тестах показ клавиатуры не влиял на значения высоты, используемые для оценки медиазапросов.
ЛКМ

Я могу подтвердить: высота: 250 пикселей работал для меня (на Android, по крайней мере).
WoodrowShigeru

0

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

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

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


0

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

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


1
Добавление такого переключателя является последним средством, которое вообще не следует считать приемлемым, если только нет другого решения, которое не сломало бы приложение. Это не то, что должно блокировать создание работающего приложения.
Адам Леггетт

-2

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

Вы бы хотели как-то обработать корпус физической клавиатуры.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.