Ứng dụng web iPad: Phát hiện bàn phím ảo bằng JavaScript trong Safari?


147

Tôi đang viết một ứng dụng web cho iPad ( không phải là ứng dụng App Store thông thường - nó được viết bằng HTML, CSS và JavaScript). Vì bàn phím lấp đầy một phần lớn của màn hình, nên thay đổi bố cục của ứng dụng để phù hợp với không gian còn lại khi bàn phím được hiển thị. Tuy nhiên, tôi đã không tìm thấy cách nào để phát hiện khi nào hoặc liệu bàn phím được hiển thị.

Ý tưởng đầu tiên của tôi là giả định rằng bàn phím có thể nhìn thấy khi một trường văn bản có tiêu điểm. Tuy nhiên, khi bàn phím ngoài được gắn vào iPad, bàn phím ảo sẽ không hiển thị khi trường văn bản nhận được tiêu điểm.

Trong các thử nghiệm của tôi, bàn phím cũng không ảnh hưởng đến chiều cao hoặc chiều cao của bất kỳ thành phần DOM nào và tôi không tìm thấy sự kiện hay thuộc tính độc quyền nào cho biết bàn phím có hiển thị hay không.


1
Hừm, vấn đề thú vị. Hãy thử lặp lại các đối tượng của "cửa sổ" trên Safari của iPad để xem có đối tượng đặc biệt nào liên quan đến hỗ trợ bàn phím không.
David Murdoch

@David không hoạt động, bàn phím không phải là "cửa sổ" Javascript.
kennytm

2
@KennyTM. Tât nhiên. Nhưng có thể có một cờ liên quan đến màn hình bàn phím trên màn hình trong bất kỳ đối tượng nào của cửa sổ. Đó là giá trị một shot.
David Murdoch

1
Tôi đã thử nó. Không tìm thấy gì, thật không may. Cũng so sánh tất cả các thuộc tính cửa sổ sâu ba cấp trước và sau khi hiển thị bàn phím. Không có sự khác biệt nào có vẻ liên quan như các chỉ số cho bàn phím.
LKM

3
Có một câu trả lời mới hơn cho điều này ??
fraxture

Câu trả lời:


54

Tôi tìm thấy một giải pháp hiệu quả, mặc dù nó hơi xấu. Nó cũng sẽ không hoạt động trong mọi tình huống, nhưng nó hoạt động với tôi. Vì tôi điều chỉnh kích thước giao diện người dùng với kích thước cửa sổ của iPad, nên người dùng thường không thể cuộn. Nói cách khác, nếu tôi đặt scrollTop của cửa sổ, nó sẽ giữ ở mức 0.

Mặt khác, nếu bàn phím được hiển thị, cuộn đột ngột hoạt động. Vì vậy, tôi có thể đặt scrollTop, ngay lập tức kiểm tra giá trị của nó và sau đó đặt lại. Đây là cách nó có thể tìm trong mã, sử dụng 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 ');
    });
});

Thông thường, bạn sẽ mong đợi điều này sẽ không hiển thị cho người dùng. Thật không may, ít nhất là khi chạy trong Trình mô phỏng, iPad rõ ràng (mặc dù nhanh chóng) cuộn lên xuống một lần nữa. Tuy nhiên, nó hoạt động, ít nhất là trong một số tình huống cụ thể.

Tôi đã thử nghiệm điều này trên iPad và có vẻ như nó hoạt động tốt.


Tôi đang gặp sự cố với ứng dụng web của mình khi mà đầu vào được tập trung vào, màn hình sẽ cuộn lên một chút. Tôi đã vô hiệu hóa cuộn, nhưng vẫn cuộn này. Có ý kiến ​​gì không? Cảm ơn [ stackoverflow.com/questions/6740253/ Mạnh
Andrew Samuelsen

Tôi chưa thử điều này, nhưng có vẻ đầy hứa hẹn. Sẽ không .scrollTop(1)làm việc tốt như vậy và ít rõ ràng hơn?
ThinkingStiff

1
Đây là ý tưởng tồi ... Bàn phím có thể là bluetooth và ảo có thể không được hiển thị.
theSociableme

3
@theSociableme: Toàn bộ quan điểm của giải pháp này là xử lý bàn phím bluetooth đúng cách. Nếu bạn bỏ qua bàn phím bluetooth, hãy tìm hiểu xem bàn phím ảo có được hiển thị hay không, vì bạn chỉ cần kiểm tra xem một trường có tập trung hay không.
LKM

5
@fraxture: Không biết giải thích toàn diện (nếu bạn nghiên cứu và viết nó, tôi rất thích đọc nó). Hai nền tảng xử lý bàn phím trên màn hình trong các trình duyệt chính của chúng rất khác nhau. Android Chrome thu nhỏ chiều cao khung nhìn để nhường chỗ cho bàn phím, do đó trang sẽ thay đổi kích thước khi bàn phím được hiển thị. iOS Safari phủ lên trang bằng bàn phím (kích thước trang giữ nguyên) và thay đổi cách cuộn hoạt động. Safari cả hai cuộn trang bên trong chế độ xem và di chuyển đồng thời chế độ xem, đảm bảo rằng phần dưới của trang nằm phía trên bàn phím khi cuộn xuống hết cỡ.
LKM

32

Bạn có thể sử dụng sự kiện tập trung để phát hiện sự từ chối bàn phím. Nó giống như mờ, nhưng bong bóng. Nó sẽ kích hoạt khi bàn phím đóng lại (nhưng cũng có thể trong các trường hợp khác). Trong Safari và Chrome, sự kiện chỉ có thể được đăng ký với addEventListener, không phải bằng các phương thức cũ. Dưới đây là một ví dụ tôi đã sử dụng để khôi phục ứng dụng Phonegap sau khi loại bỏ bàn phím.

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

Không có đoạn mã này, vùng chứa ứng dụng sẽ ở vị trí cuộn lên cho đến khi làm mới trang.


1
cách khắc phục tốt nhất tôi đã tìm thấy cho vấn đề của mình
Sutulustus


1
Ngoài ra, bạn có thể sử dụng phiên bản 'tập trung' để phát hiện mở bàn phím.
A.Çetin

15

có lẽ một giải pháp tốt hơn một chút là liên kết (với jQuery trong trường hợp của tôi) sự kiện "làm mờ" trên các trường đầu vào khác nhau.

Điều này bởi vì khi bàn phím biến mất, tất cả các trường mẫu bị mờ. Vì vậy, đối với tình huống của tôi, snipped này đã giải quyết vấn đề.

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

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

});

hy vọng nó giúp. Michele


Cảm ơn câu trả lời này. Tôi thấy nó hữu ích để giải quyết vấn đề trong đó bàn phím iPad Safari khiến con trỏ textarea bị dịch chuyển (offset) bên ngoài textarea.
kennbrodhagen

14

Nếu có bàn phím trên màn hình, việc tập trung vào trường văn bản ở gần cuối khung nhìn sẽ khiến Safari cuộn trường văn bản vào chế độ xem. Có thể có một số cách để khai thác hiện tượng này để phát hiện sự hiện diện của bàn phím (có một trường văn bản nhỏ ở cuối trang để lấy nét ngay lập tức hoặc một cái gì đó tương tự).


1
Đó là một ý tưởng khéo léo. Tôi tìm thấy một giải pháp tương tự cũng sử dụng vị trí cuộn hiện tại để phát hiện bàn phím ảo.
LKM

rực rỡ! bạn đã cứu ngày của tôi!
aztack

11

Trong sự kiện lấy nét, bạn có thể cuộn qua chiều cao tài liệu và kỳ diệu là window.innerHeight được giảm theo chiều cao của bàn phím ảo. Lưu ý rằng kích thước của bàn phím ảo là khác nhau đối với hướng ngang so với hướng dọc, do đó bạn sẽ cần phải phát hiện lại khi thay đổi. Tôi sẽ khuyên bạn không nên nhớ các giá trị này vì người dùng có thể kết nối / ngắt kết nối bàn phím bluetooth bất cứ lúc nào.

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

Lưu ý rằng khi người dùng đang sử dụng bàn phím bluetooth, bàn phímHeight là 44, chiều cao của thanh công cụ [trước] [tiếp theo].

Có một chút nhấp nháy khi bạn thực hiện phát hiện này, nhưng dường như không thể tránh được.


5
Tôi mới thử cái này trong iOS 8.2 và nó không hoạt động ... nó có ngừng hoạt động ở giai đoạn nào đó cho iOS mới không?
Minh

1
Tôi cũng không làm việc cho tôi - thay đổi kích thước không được kích hoạt trong iOS9.3
llamerr

8

Chỉnh sửa: Tài liệu của Apple mặc dù tôi thực sự không thể làm cho nó hoạt động: WKWebView Hành vi với bàn phím Hiển thị : "Trong iOS 10, các đối tượng WKWebView khớp với hành vi gốc của Safari bằng cách cập nhật thuộc tính window.innerHeight khi bàn phím được hiển thị và không gọi thay đổi kích thước sự kiện "(có lẽ có thể sử dụng tiêu điểm hoặc tiêu điểm cộng với độ trễ để phát hiện bàn phím thay vì sử dụng thay đổi kích thước).

Chỉnh sửa: mã giả định bàn phím trên màn hình, không phải bàn phím ngoài. Rời khỏi nó vì thông tin có thể hữu ích cho những người khác chỉ quan tâm đến bàn phím trên màn hình. Sử dụng http://jsbin.com/AbimiQup/4 để xem thông số trang.

Chúng tôi kiểm tra xem liệu document.activeElementphần tử có hiển thị bàn phím không (kiểu nhập = văn bản, textarea, v.v.).

Đoạn mã sau làm mờ đi mọi thứ cho mục đích của chúng tôi (mặc dù nói chung không chính xác).

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

Đoạn mã trên chỉ là gần đúng: Đó là sai đối với bàn phím tách, bàn phím không khóa, bàn phím vật lý. Theo nhận xét ở đầu, bạn có thể thực hiện công việc tốt hơn mã đã cho trên Safari (kể từ iOS8?) Hoặc WKWebView (kể từ iOS10) bằng cách sử dụng thuộc window.innerHeighttính.

Tôi đã tìm thấy thất bại trong các trường hợp khác: ví dụ: tập trung vào đầu vào, sau đó vào màn hình chính rồi quay lại trang; iPad không nên làm cho khung nhìn nhỏ hơn; Các trình duyệt IE cũ sẽ không hoạt động, Opera không hoạt động vì Opera tiếp tục tập trung vào phần tử sau khi đóng bàn phím.

Tuy nhiên, câu trả lời được gắn thẻ (thay đổi cuộn để đo chiều cao) có tác dụng phụ UI khó chịu nếu chế độ xem có thể phóng to (hoặc thu phóng lực trong tùy chọn). Tôi không sử dụng giải pháp được đề xuất khác (thay đổi cuộn) vì trên iOS, khi chế độ xem có thể phóng to và cuộn sang đầu vào tập trung, có các tương tác lỗi giữa cuộn & thu phóng & lấy nét (có thể để đầu vào chỉ tập trung bên ngoài chế độ xem - không có thể nhìn thấy).


Tùy thuộc vào trình duyệt InternalHeight để phát hiện các ngắt toàn màn hình khi một số thành phần được định vị tuyệt đối. Không đáng tin cậy chút nào.
Udo

5

Chỉ được thử nghiệm trên Android 4.1.1:

sự kiện làm mờ không phải là một sự kiện đáng tin cậy để kiểm tra bàn phím lên xuống vì người dùng là tùy chọn ẩn rõ ràng bàn phím không kích hoạt sự kiện mờ trên trường khiến bàn phím hiển thị.

Thay đổi kích thước sự kiện tuy nhiên hoạt động như một bùa mê nếu bàn phím lên hoặc xuống vì bất kỳ lý do nào.

cà phê:

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

cháy bất cứ lúc nào bàn phím được hiển thị hoặc ẩn vì bất kỳ lý do.

Tuy nhiên, xin lưu ý trong trường hợp trình duyệt Android (chứ không phải ứng dụng) có một thanh url có thể thu vào, không kích hoạt thay đổi kích thước khi được rút lại nhưng không thay đổi kích thước cửa sổ có sẵn.


+1 cho sự kiện mờ không kích hoạt khi tắt bàn phím bằng tay. Thay đổi kích thước là một ý tưởng tốt và nó sẽ hoạt động tốt cho các thiết bị Android.
Ankit Garg

Có thể xác nhận rằng điều này hoạt động trên cả iPhone 5 (iOS 6.0.2) và iPad 3 (iOS 6.0).
Diego Agulló

1
Chỉ được thử nghiệm trên Chrome 41 trên iOS6 trên CrossBrowserTesting - thay đổi kích thước không được kích hoạt bởi bàn phím ảo xuất hiện hoặc biến mất.
Dan Dascalescu

4

Thay vì phát hiện bàn phím, hãy thử phát hiện kích thước của cửa sổ

Nếu chiều cao của cửa sổ bị giảm và chiều rộng vẫn như cũ, điều đó có nghĩa là bàn phím đang bật. Khác, bàn phím tắt, bạn cũng có thể thêm vào đó, kiểm tra xem có bất kỳ trường nhập liệu nào được lấy nét hay không.

Hãy thử mã này chẳng hạn.

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
Điều đó dường như không còn hoạt động nữa trong iOS 8. Bàn phím phủ lên nội dung và trong nhiều trường hợp, nội dung cuộn xuống che khuất các trường nhập liệu tập trung ban đầu.
Rick Strahl

3
chiều cao cửa sổ trả về chiều cao bao gồm cả bàn phím kể từ iOS 7, trong cửa sổ IOS 6. điều này sẽ thay đổi khi bàn phím mở.
Michiel

1
Lưu ý rằng chiều cao cũng thay đổi khi thanh địa chỉ trên cùng trượt vào và ra khỏi màn hình khi cuộn. Bạn nên thêm một thay đổi chiều cao tối thiểu, tôi muốn nói là 200px (chưa được kiểm tra).
oriadam

1

Giải pháp này ghi nhớ vị trí cuộn

    var currentscroll = 0;

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

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

        $(window).scrollTop(currentscroll);

        }
    });

1

Hãy thử cái này:

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

Như đã lưu ý trong các câu trả lời trước ở đâu đó, biến window.innerHeight được cập nhật chính xác ngay bây giờ trên iOS10 khi bàn phím xuất hiện và vì tôi không cần hỗ trợ cho các phiên bản trước nên tôi đã đưa ra bản hack sau có thể dễ dàng hơn một chút sau đó thảo luận "các giải pháp".

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

sau đó bạn có thể sử dụng:

if (window.innerHeight != windowExpectedSize){ ... }

để kiểm tra xem bàn phím có nhìn thấy không. Bây giờ tôi đã sử dụng nó trong ứng dụng web của mình và nó hoạt động tốt, nhưng (như tất cả các giải pháp khác) bạn có thể thấy tình huống không thành công vì kích thước "mong đợi" không được cập nhật đúng cách hoặc một cái gì đó.


Tôi đã hy vọng đây là trường hợp, nhưng không, nó không được cập nhật.
Sam Saffron

0

Tôi đã thực hiện một số tìm kiếm và tôi không thể tìm thấy bất cứ điều gì cụ thể cho "trên bàn phím hiển thị" hoặc "trên bàn phím bị loại bỏ". Xem danh sách chính thức của các sự kiện được hỗ trợ . Xem thêm Ghi chú kỹ thuật TN2262 cho iPad. Như bạn có thể đã biết, có một sự kiện cơ thể onorientationchangebạn có thể kết nối để phát hiện phong cảnh / chân dung.

Tương tự, nhưng một phỏng đoán hoang dã ... bạn đã thử phát hiện thay đổi kích thước chưa? Thay đổi chế độ xem có thể kích hoạt sự kiện đó gián tiếp từ bàn phím được hiển thị / ẩn.

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

Mà chỉ đơn giản là cảnh báo chiều cao mới trên bất kỳ sự kiện thay đổi kích thước nào ....


10
Thật không may, trong các thử nghiệm của tôi, bàn phím không kích hoạt sự kiện thay đổi kích thước.
LKM

0

Tôi đã không tự mình thử điều này, vì vậy đây chỉ là một ý tưởng ... nhưng bạn đã thử sử dụng các truy vấn phương tiện với CSS để xem khi nào chiều cao của cửa sổ thay đổi và sau đó thay đổi thiết kế cho điều đó? Tôi sẽ tưởng tượng rằng Safari di động không nhận ra bàn phím là một phần của cửa sổ để hy vọng nó sẽ hoạt động.

Thí dụ:

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

2
Ý tưởng rất thông minh. Thật không may, trong các thử nghiệm của tôi, hiển thị bàn phím không ảnh hưởng đến các giá trị chiều cao được sử dụng để đánh giá các truy vấn phương tiện.
LKM

Tôi có thể xác nhận: height: 250px làm việc cho tôi (ít nhất là trên Android).
WoodrowShigeru

0

Vấn đề là, ngay cả trong năm 2014, các thiết bị xử lý thay đổi kích thước màn hình sự kiện, cũng như các sự kiện cuộn, không nhất quán trong khi bàn phím mềm đang mở.

Tôi đã thấy rằng, ngay cả khi bạn đang sử dụng bàn phím bluetooth, iOS đặc biệt gây ra một số lỗi bố cục lạ; Vì vậy, thay vì phát hiện bàn phím mềm, tôi chỉ phải nhắm mục tiêu các thiết bị rất hẹp và có màn hình cảm ứng.

Tôi sử dụng truy vấn phương tiện (hoặc window.matchMedia ) để phát hiện chiều rộng và Modernizr để phát hiện sự kiện chạm.


0

Có lẽ dễ dàng hơn để có một hộp kiểm trong cài đặt ứng dụng của bạn, nơi người dùng có thể chuyển đổi 'bàn phím ngoài được đính kèm?'.

Trong bản in nhỏ, giải thích cho người dùng rằng bàn phím ngoài hiện không thể phát hiện được trong các trình duyệt ngày nay.


1
Thêm một chuyển đổi như đây là biện pháp cuối cùng không nên được coi là chấp nhận được trừ khi không có giải pháp nào khác sẽ không phá vỡ ứng dụng. Đây không phải là thứ nên chặn để tạo ra một ứng dụng hoạt động.
Adam Leggett

-2

Chà, bạn có thể phát hiện khi hộp đầu vào của bạn có tiêu điểm và bạn biết chiều cao của bàn phím. Ngoài ra còn có CSS ​​để có được hướng của màn hình, vì vậy tôi nghĩ bạn có thể hack nó.

Bạn sẽ muốn xử lý trường hợp của một bàn phím vật lý bằng cách nào đó, mặc dù.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.