Веб-додаток iPad: Виявлення віртуальної клавіатури за допомогою JavaScript у Safari?


147

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

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

У моїх експериментах клавіатура також не впливала на висоту або висоту прокрутки жодного з елементів DOM, і я не знайшов жодних фірмових подій або властивостей, які б вказували, чи клавіатура видима.


1
Гм, цікава проблема. Спробуйте переглядати об’єкти "вікна" на iPad Safari, щоб побачити, чи є якісь спеціальні об'єкти, пов'язані з підтримкою клавіатури.
Девід Мердок

@Давид, який не працюватиме, клавіатура не є "вікном Javascript".
kennytm

2
@KennyTM. Дух. Але в будь-якому з об’єктів вікна може бути прапор, пов’язаний із відображенням на екрані клавіатури. Варто зняти.
Девід Мердок

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)так добре і бути менш очевидним?
ДумаючиСтиф

1
Це погана ідея ... Клавіатура може бути Bluetooth, а віртуальна може не відображатися.
theSociableme

3
@theSociableme: Вся суть цього рішення полягає в правильному поводженні з клавіатурою Bluetooth. Якщо ви проігнорували клавіатури Bluetooth, зрозуміти, чи відображається віртуальна клавіатура, було б просто, оскільки ви могли просто перевірити, чи поле фокусується.
LKM

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

32

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

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

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


1
найкраще виправлення, яке я знайшов для своєї проблеми
Sutulustus


1
Також ви можете використовувати "focusin" версію для виявлення відкритої клавіатури.
А.Çetin

15

можливо, трохи кращим рішенням є зв’язування (з моїм випадком jQuery) події "розмиття" у різних полях введення.

Це тому, що коли клавіатура зникає, всі форми форми розмиваються. Тож для моєї ситуації ця обробка вирішила проблему.

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

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

});

сподіваюся, що це допомагає. Мікеле


Дякую за цю відповідь. Мені здається корисним вирішити проблему, коли клавіатура iPad Safari спричинила зміщення курсору textarea (зміщення) за межами textarea.
kennbrodhagen

14

Якщо є екранна клавіатура, фокусування текстового поля, яке знаходиться внизу вікна перегляду, призведе до того, що Safari прокручує текстове поле в поле перегляду. Можливо, є якийсь спосіб використати це явище, щоб виявити наявність клавіатури (з крихітним текстовим полем внизу сторінки, яке на мить отримує фокус, або щось подібне).


1
Це геніальна ідея. Я знайшов подібне рішення, яке також використовує поточну позицію прокрутки для виявлення віртуальної клавіатури.
LKM

блискучий! ти врятував мені день!
aztack

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 Behavior with Keyboard Display : "В 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 залишала фокус на елементі після закриття клавіатури.

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


Залежно від InternalHeight веб-переглядачів для виявлення розривів повноекранного екрану, коли деякі елементи розташовані абсолютно. Не зовсім надійний.
Удо

5

Тестується лише на Android 4.1.1:

подія розмиття не є надійною подією для тестування клавіатури вгору та вниз, оскільки користувач як можливість явно приховати клавіатуру, що не викликає події розмиття на полі, яке спричинило показ клавіатури.

подія resize, однак, працює як шарм, якщо клавіатура піднімається або знижується з будь-якої причини.

кава:

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

пожежі на будь-який час, коли клавіатура відображається або приховується з будь-якої причини.

Однак зверніть увагу на те, що у випадку з андроїд-браузером (а не з додатком) є висувна панель URL-адреси, яка не змінює розмір, коли її втягується, але змінює доступний розмір вікна.


+1 за розмиття події, яка не спрацьовує при ручному відхиленні клавіатури. Resize - хороша ідея, і вона буде добре працювати на пристроях 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 window.height змінюється, коли клавіатура відкривається.
Міхель

1
Зауважте, що висота також змінюється, коли верхня адресна панель ковзає вгору та поза екраном під час прокрутки. Ви повинні додати мінімальну зміну висоти, я б сказав, 200 пікселів (не перевірено).
oriadam

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 не розпізнає клавіатуру як частину вікна, щоб, сподіваємось, спрацювало.

Приклад:

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

2
Дуже розумна ідея. На жаль, у моїх тестах показ клавіатури не впливав на значення висоти, що використовуються для оцінки медіа-запитів.
LKM

Я можу підтвердити: висота: для мене працювала 250px (принаймні, на Android).
WoodrowShigeru

0

Проблема полягає в тому, що навіть у 2014 році пристрої обробляють події зміни розміру екрана, а також події прокрутки, непослідовно, коли м'яка клавіатура відкрита.

Я виявив, що навіть якщо ви використовуєте клавіатуру Bluetooth, iOS, зокрема, запускає деякі дивні помилки компонування; тож замість виявлення м’якої клавіатури мені довелося орієнтуватися на дуже вузькі пристрої та сенсорні екрани.

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


0

Можливо, у налаштуваннях додатка простіше встановити прапорець, у якому користувач може перемикати "зовнішню клавіатуру?".

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


1
Додавання перемикача, такого як це, є крайнім засобом, який взагалі не слід вважати прийнятним, якщо не існує іншого рішення, яке не порушить додаток. Це не те, що повинно стати блокатором для створення функціонуючого додатка.
Адам

-2

Ну, ви можете визначити, коли фокус у ваших полях вводу, і ви знаєте висоту клавіатури. Існує також CSS, щоб отримати орієнтацію екрана, тому я думаю, ви можете зламати його.

Хоча ви хочете якось обробити справи фізичної клавіатури.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.