Веб-приложение для iPad: обнаружение виртуальной клавиатуры с помощью JavaScript в Safari?
Я пишу веб-приложение для iPad (не обычное приложение App Store - оно написано с использованием HTML, CSS и JavaScript). Поскольку клавиатура занимает большую часть экрана, имеет смысл изменить макет приложения, чтобы он соответствовал оставшемуся пространству при отображении клавиатуры. Тем не менее, я не нашел способа определить, когда или отображается ли клавиатура.
Моей первой идеей было предположить, что клавиатура видна, когда текстовое поле имеет фокус. Однако когда к iPad подключена внешняя клавиатура, виртуальная клавиатура не отображается, когда текстовое поле получает фокус.
В моих экспериментах клавиатура также не влияла на высоту или высоту прокрутки ни одного из элементов DOM, и я не обнаружил собственных событий или свойств, которые указывают, видна ли клавиатура.
20 ответов
Я нашел решение, которое работает, хотя это немного некрасиво. Это также не будет работать в любой ситуации, но это работает для меня. Поскольку я адаптирую размер пользовательского интерфейса к размеру окна 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, и, кажется, работает нормально.
Вы можете использовать событие focusout для обнаружения отклонения клавиатуры. Это как размытие, но пузыри. Он будет срабатывать при закрытии клавиатуры (но, конечно, и в других случаях). В Safari и Chrome событие может быть зарегистрировано только с addEventListener, но не с устаревшими методами. Вот пример, который я использовал для восстановления приложения Phonegap после отключения клавиатуры.
document.addEventListener('focusout', function(e) {window.scrollTo(0, 0)});
Без этого фрагмента контейнер приложения оставался в положении прокрутки до обновления страницы.
Может быть, немного лучшим решением будет связать (с jQuery в моем случае) событие "размытия" в различных полях ввода.
Это потому, что когда клавиатура исчезает, все поля формы размываются. Так что для моей ситуации это отрубило, решило проблему.
$('input, textarea').bind('blur', function(e) {
// Keyboard disappeared
window.scrollTo(0, 1);
});
Надеюсь, поможет. Michele
Если есть экранная клавиатура, фокусировка текстового поля в нижней части окна просмотра заставит Safari прокрутить текстовое поле в поле зрения. Может быть какой-то способ использовать это явление для обнаружения присутствия клавиатуры (наличие крошечного текстового поля внизу страницы, которое мгновенно фокусируется, или что-то в этом роде).
Редактировать: документально подтверждено 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://stackru.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, когда область просмотра масштабируется и прокручивается до сфокусированного ввода, между прокруткой, масштабированием и фокусировкой возникают ошибочные взаимодействия (которые могут оставить только сфокусированный ввод за пределами области просмотра - не виден).
Визуальное окно просмотра API - сделан для реагирования на виртуальные изменения клавиатуры и видимость окна просмотра.
API визуального окна просмотра предоставляет явный механизм для запроса и изменения свойств визуального окна просмотра. Визуальное окно просмотра - это визуальная часть экрана, за исключением экранных клавиатур, областей за пределами области масштабирования пальцем или любого другого экранного артефакта, который не масштабируется с размерами страницы.
function viewportHandler() {
var viewport = event.target;
console.log('viewport.height', viewport.height)
}
window.visualViewport.addEventListener('scroll', viewportHandler);
window.visualViewport.addEventListener('resize', viewportHandler);
Во время события фокуса вы можете прокручивать высоту документа и волшебным образом 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, что является высотой [предыдущей][следующей] панели инструментов.
Когда вы делаете это обнаружение, появляется небольшое мерцание, но кажется, что избежать этого невозможно.
Проверено только на Android 4.1.1:
Событие размытия не является надежным событием для тестирования клавиатуры вверх и вниз, потому что у пользователя есть возможность явно скрыть клавиатуру, которая не вызывает событие размытия в поле, которое вызвало отображение клавиатуры.
Событие resize, однако, работает как чудо, если клавиатура поднимается или опускается по любой причине.
кофе:
$(window).bind "resize", (event) -> alert "resize"
срабатывает в любое время, когда клавиатура отображается или скрывается по любой причине.
Однако обратите внимание на то, что в случае браузера Android (а не приложения) есть убирающаяся панель URL, которая не вызывает изменение размера, когда оно убирается, но меняет доступный размер окна.
Вместо того, чтобы определять клавиатуру, попробуйте определить размер окна
Если высота окна была уменьшена, а ширина все та же, это означает, что клавиатура включена. Если клавиатура выключена, вы также можете добавить к ней, проверить, находится ли какое-либо поле ввода в фокусе или нет.
Попробуйте этот код, например.
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()));
}
});
Вот небольшая библиотека, которую я создал, вы можете использовать ее для создания окна просмотра, которое Just Works(TM)
Идея состоит в том, чтобы добавить фиксированный div внизу. Когда отображается виртуальная клавиатура / происходит скрытое событие прокрутки. Плюс узнаем высоту клавиатуры
Как отмечалось в предыдущих ответах где-то, переменная 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){ ... }
проверить, видна ли клавиатура. Я уже некоторое время использую его в своем веб-приложении, и оно работает хорошо, но (как и во всех других решениях) вы можете столкнуться с ситуацией, когда он не работает, потому что "ожидаемый" размер не обновляется должным образом или что-то в этом роде.
Это решение запоминает положение прокрутки
var currentscroll = 0;
$('input').bind('focus',function() {
currentscroll = $(window).scrollTop();
});
$('input').bind('blur',function() {
if(currentscroll != $(window).scrollTop()){
$(window).scrollTop(currentscroll);
}
});
Попробуй это:
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`
Возможно, в настройках вашего приложения проще установить флажок, чтобы пользователь мог переключать "внешняя клавиатура подключена?".
Мелким шрифтом объясните пользователю, что внешние клавиатуры в настоящее время не обнаруживаются в современных браузерах.
Проблема заключается в том, что даже в 2014 году устройства обрабатывают события изменения размера экрана, а также события прокрутки, непостоянно, когда программная клавиатура открыта.
Я обнаружил, что даже если вы используете Bluetooth-клавиатуру, iOS, в частности, вызывает некоторые странные ошибки в макете; поэтому вместо того, чтобы обнаруживать программную клавиатуру, я просто нацелился на устройства, которые очень узкие и имеют сенсорные экраны.
Я использую медиа-запросы (или window.matchMedia) для определения ширины и Modernizr для обнаружения событий касания.
В браузере 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
Ну, вы можете определить, когда ваши поля ввода имеют фокус, и вы знаете высоту клавиатуры. Существует также CSS, чтобы получить ориентацию экрана, поэтому я думаю, что вы можете взломать его.
Вы бы хотели как-нибудь разобраться со случаем физической клавиатуры.
Я немного искал и не мог найти ничего конкретного для "на клавиатуре" или "на клавиатуре отклонено". Смотрите официальный список поддерживаемых событий. Также см. Техническую ноту TN2262 для iPad. Как вы, наверное, уже знаете, есть событие тела onorientationchange
Вы можете подключиться, чтобы обнаружить пейзаж / портрет.
Точно так же, но дикая догадка... Вы пытались обнаружить изменение размера? Изменения области просмотра могут вызвать это событие косвенно с отображаемой / скрытой клавиатуры.
window.addEventListener('resize', function() { alert(window.innerHeight); });
Который просто предупредит новую высоту при любом изменении размера....
Я не пытался сделать это сам, так что это всего лишь идея... но вы пытались использовать медиа-запросы с CSS, чтобы увидеть, когда изменяется высота окна, а затем изменить дизайн для этого? Я полагаю, что Safari mobile не распознает клавиатуру как часть окна, и это, надеюсь, сработает.
Пример:
@media all and (height: 200px){
#content {height: 100px; overflow: hidden;}
}