標籤:jpg get ons 推薦 his usb manage field fun
從互動層面上來講,完成一個功能(獲得想要的資訊)的過程稱之為使用者路徑。使用者路徑越長,完成功能的複雜度就越高,使用者體驗也就越差。因此當開啟一個需要使用者填寫資訊的表單介面時,為了提高可用性,PC 端一般會將游標聚焦到對應輸入框(input),移動端也是同理,讓對應的 input 獲得 focus 狀態,喚起軟鍵盤,方便使用者直接輸入。
本文暫且不論 PC 端的情境,在移動端(iOS、Android)實現這個看似不起眼的效果其實是需要經過一番折騰,我們慢慢往下看以下三種常用情境。
一、當進入表單頁時,讓軟鍵盤自動開啟
這個需求比較常見,但是也是最棘手的。講科學的話,我們可以直接在 JS 裡擷取 input ,給它 focus 下就搞定了。但是這在移動端瀏覽器裡是行不通的。。
另外,H5 提供了 autofocus 屬性,這個屬性的相容性在 caniuse 上顯示並不支援 iOS Safari,Android 也是要到 4.4 才開始支援,因此我們可以忽略這個屬性,不過下文會再次提到這個屬性。
因此在 iOS 裡想要在頁面 load 完成後自動聚焦 input,開啟鍵盤目前來講不是很現實。
最難過的是 Android 也不行,目前進行了簡單的測試系統瀏覽器和 App 內嵌 WebView,H5 中的 input 是聚焦狀態,但是無法喚起鍵盤,鍵盤,鍵盤。。。
情境一,暫時無解……(下文提到在 Hybrid App 中可以實現)
二、當點擊頁面中某個元素喚起軟鍵盤
這個相對於情境一,多了使用者互動這一步。那麼這樣是不是就可以使用 JS 在 iOS 上成功的喚起鍵盤了呢?答案是肯定的。
<!-- HTML -->
<input id="input" type="text" placeholder="this a input"/>
<button id="J-focus-btn" onclick="clickFocusBtn()">focus input</button>
// JS
function clickFocusBtn() {
document.getElementById("input").focus();
}
如果有使用 zepto 的童鞋,這邊需要注意下為了 iOS,你不能使用 tap 事件。
// JS zepto
$(‘#J-focus-btn‘).on(‘tap‘, function() {
$(‘#input‘).focus();
});
如上使用了 zepto tap 事件,它在 iOS 上並不能達到預期效果,這裡面就涉及到了 iOS WebView 的一種預設安全機制。在 UIWebView 中有一個屬性:
@property (nonatomic) BOOL keyboardDisplayRequiresUserAction NS_AVAILABLE_IOS(6_0); // default is YES
這個屬性預設是 YES,也就是說鍵盤的出現必須要使用者互動。那我們就知道原因了,zepto 內部觸發 tap 事件是在 setTimeout 內,也就是說執行 focus 時,執行環境並不是使用者觸發的,因此 focus 被攔截掉了。
// zepto
tapTimeout = setTimeout(function() {
// trigger event
}, 0)
如果我們是寫 Hybird App 的頁面,則可以讓 Native Coder 將 UIWebView 的 keyboardDisplayRequiresUserAction 屬性設定為 NO,則不必操心這個問題了。
不過 iOS 的 WKWebView 不支援這個屬性了,但是在 StackOverflow 上有方案,可以使用 runtime 的 method swizzling hack 掉,詳見此連結 stackoverflow.com/questions/3…
那麼情境一在自己的 Hybrid App 裡還是可以實現的,當然系統原生的 Safari 瀏覽器我們無能為力,能最佳化一點是一點吧。
同時測試了下 autofocus 屬性,在 keyboardDisplayRequiresUserAction 設定為 NO 的情況下,它也是能正常工作的。
在 Android 底下,也是可以實現使用者點擊之後 focus 指定 input 的效果,而且沒有 iOS 的那個機制。
三、表單頁多個 input 依次自動聚焦
這個情境其實是情境一、二的結合,綜合上面兩個情境的測試分析,在自己的 * iOS Hybrid App * 裡依賴 Native 的 WebView 是可以實現的,在 Android 和外部瀏覽器中可以實現除第一次聚焦外的自動聚焦。。
目前 iOS UIWebView 設定 keyboardDisplayRequiresUserAction = NO 的狀態下,需要在 blur 事件內延遲 focus 才會生效(具體原因暫時不明):
// Hybrid App 內
document.querySelector(‘#input1‘).focus();
document.querySelector(‘#input1‘).addEventListener(‘blur‘, function() {
setTimeout(function() { // 必須延遲
document.querySelector(‘#input2‘).focus();
}, 200);
});
在系統 Safari 內,則因為 keyboardDisplayRequiresUserAction 預設為 YES,因此不允許在使用者互動產生的執行環境之外調用 focus,因此不能順延強制。
// 系統 Safari 內
document.querySelector(‘#input1‘).focus();
document.querySelector(‘#input1‘).addEventListener(‘blur‘, function() {
document.querySelector(‘#input2‘).focus();
});
而在安卓中,頁面載入完後自動聚焦仍舊只是出現游標,不彈出鍵盤。。。後續自動聚焦則沒問題,如所示狀態。。。
為瞭解決這個問題,在 Hybrid App 中可以通過 JSBridge 讓 Android 原生進行喚起,後續 blur 事件中再 focus 則不需要原生再進行處理。
// Android 喚起鍵盤
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(view, 0); // view 為當前 webview
小結
總結下:
要實現頁面載入完成後自動聚焦到 input 並彈出鍵盤,依賴 iOS App 的 WebView 將 keyboardDisplayRequiresUserAction 設定為 NO,就可以支援。Android 底下只能依賴 JSBridge 調用 Android 原生方法喚起鍵盤 。
點擊元素聚焦指定 input,iOS / Android 都支援,但是 iOS 中必須保證 focus 是在使用者操作事件的函數執行環境中直接調用(Zepto tap 的坑)。
依次聚焦 input,iOS 中有點特殊,具體還是看上文情境三。。。
LINKS
移動端 Web 頁 input 控制軟鍵盤