是時候為各式裝置適配完善的輸入支援了

語言: CN / TW / HK

隨著技術進步以及跨平臺應用的普及,您的 Android 應用已經不再侷限於在直板觸屏裝置運行了。更豐富的互動方式使得使用者能夠以更復雜的輸入方式使用您的應用。所以作為開發者,是時候考慮為各種各樣的裝置提供強大的輸入支援了。本文為您準備了關於更廣泛、強大的輸入支援的分享,歡迎您閱讀。

如果您更喜歡通過影片瞭解此內容,請 點選此處 檢視。

對於各種 Android 裝置來說,輸入 (input) 是決定使用者應用體驗的關鍵要素之一。開發者通常希望使用者互動方式能儘可能簡單直觀,但是假如您新買了一個可摺疊裝置,附贈了一款鍵盤,而您喜歡的應用卻不支援標準按鍵操作,這種體驗將非常令人沮喪。

目前許多 Android 裝置內建了非觸控輸入 (non-touch input),比如 Chromebook 鍵盤,甚至一些裝置將其作為標配提供。那麼在諸如手機、可摺疊裝置、平板電腦、Chromebook、支援外接顯示屏的 Chromebox、帶內建顯示器的 Chromebase、Android TV 等各種 Android 裝置型別中,開發者應該如何確保不同的輸入方式適用於自己的應用。

△ 多種 Android 裝置

△ 多種 Android 裝置

要知道並非所有的使用者都使用手機觸控式螢幕與您的應用互動,一部分使用者可能使用的是鍵盤和觸控筆等,甚至一部分使用者有 無障礙 需求。那麼每位開發者都有必要花些時間去思考,如何使應用為儘可能多的使用者帶來愉快的使用體驗?

增強輸入 (Enhanced input)

△ 標準輸入方式和增強輸入方式

△ 標準輸入方式和增強輸入方式

對於每種型別的輸入裝置,我們可以將應用的功能分為標準用例和增強用例兩大類:

  • 標準用例包括選擇、文字輸入、長按和右鍵點選等這些使用者所期望的功能,處理此類用例的技術實現比較簡單且在某些情況下可以自動執行。如果想要為應用提供更多獨特和增強的支援,則需要開發者多加考慮。

  • 在增強用例中,某些功能不只是有了更好,而可能是必需具備的,例如一款不支援遊戲手柄的手機遊戲和一款不支援標準複製和貼上快捷鍵的文字編輯器,都是無法受到使用者歡迎的。

在提供基礎功能外,要考慮新增獨特且能為使用者提供支援的功能,這才是開發者讓自己應用真正脫穎而出的方法。例如,如下所示的 eDJing 這款應用,它添加了對鍵盤打碟和觸控板搓碟以及 MIDI DJ 控制器的支援,使用者手中的手機或 Chromebook 就能夠立即搖身一變成為 DJ 工作站。

△ eDJing 應用使用場景

△ eDJing 應用使用場景

Cubasis 是一款一流的數字音訊工作站應用,它釋出了基於 Chrome OS 作業系統優化的新版本,憑藉大螢幕的優勢以及 MIDI 控制器連線 Chromebook 的便利性,不僅增強了功能,還提升了應用實用性。

△ Cubasis 應用使用場景

△ Cubasis 應用使用場景

繪圖類應用則更加註重: 藍芽和 USB 繪圖板能夠持續正常的工作,以及在 Chrome OS 作業系統中將低延遲觸控筆 API 應用到繪圖和繪畫應用中。

△ 繪圖類應用使用場景

△ 繪圖類應用使用場景

簡而言之,使用者希望能在您的應用中獲得獨特、愉悅、直觀的體驗,而這種體驗由您來打造!

鍵盤輸入支援

鍵盤被內建在 Chromebook 中,或是成為使用者在使用可拆卸裝置、平板電腦、可摺疊裝置和電視過程中日常體驗的一部分。好訊息是大多數基本鍵盤輸入通常可以直接使用,除非您正致力於構建自己的螢幕鍵盤或從頭開始編寫自己的文字輸入檢視。

傳送鍵支援 (KEYCODE_ENTER)

開發者需要在標準的 EditText 檢視中為 Enter 鍵建立一個新行。如果您的應用中有聊天功能、反饋表單、簡報註冊或任何需要傳送文字的功能,那麼預設的換行行為肯定不是您所期望的,不用擔心的是您所預期的傳送功能很容易實現。

△ 聊天傳送文字

△ 聊天傳送文字

開發者需要在標準的 EditText 檢視中為 Enter 鍵建立一個新行,此處顯示了按下 Enter 鍵的程式碼,完整程式碼如下所示:

override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    when (keyCode) {
        KEYCODE_ENTER -> {     // 撤銷 onKeyUp 並監聽 KEYCODE_ENTER
            sendMessage()
            return true     // 如果應用已處理按鍵事件則確保返回 true
        }
    }
    // 如果沒有處理事件,則交回系統處理
    return super.onKeyUp(keyCode, event)  // 如果沒有則將事件傳遞給 super
}

媒體鍵支援 (Media key)

如果您的應用希望支援媒體播放,則還需要包含媒體鍵支援。為此請將 Enter 鍵程式碼中的 KEYCODE_ENTER 替換為您希望支援的媒體鍵程式碼即可,比如這裡使用了 MEDIA_NEXT 和 MEDIA_PREV。此外請不要忘記使用 SPACE 以便用空格鍵來控制播放和暫停。完整程式碼如下所示:

override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    when (keyCode) {
        KEYCODE_SPACE, KEYCODE_MEDIA_PLAY_PAUSE -> {
              playOrpauseMedia(); 
              return true 
        }
        KEYCODE_MEDIA_NEXT -> {nextTrack(); return true }
        KEYCODE_MEDIA_PREV -> {prevTrack(); return true }
    }
    // 如果沒有處理事件,則交回系統處理
    return super.onKeyUp(keyCode, event)
}

遊戲鍵支援 (KEYCODE_W|A|S|D)

對於遊戲應用,您可能希望包括對箭頭鍵和 W、A、S、D 四個按鍵的支援,這同樣很簡單。您只需在 Android 文件中找到正確的 鍵程式碼,並監聽這些按鍵即可。完整程式碼如下所示:

when (keyCode) {
    KEYCODE_W, DPAD_UP -> { goUp(); return true }
    KEYCODE_A, DPAD_LEFT -> { goLeft(); return true }
    KEYCODE_S, DPAD_DOWN -> { goDown(); return true }
    KEYCODE_D, DPAD_RIGHT -> { goRight(); return true }
}

需要注意的是在提供鍵盤支援時通常要監聽 onKeyUp,這樣您就不必擔心在按住某個鍵時,將會發送重複的 onKeyDown 事件。另外如果您想確保實現毫秒級的時間響應,您可以監聽 onKeyDown 並自行處理重複的按鍵事件。完整程式碼如下所示:

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    when (keyCode) {
        KEYCODE_F -> {
            shootFireball()
            return true
        }
    }
    return super.onKeyUp(keyCode, event)
}

更多相關資訊請訪問: ChromeOS.dev

快捷鍵支援 (Ctrl+)

除了基本鍵盤按鍵,還需要考慮的是配置基於 Ctrl 的快捷鍵,複製、貼上、撤消、重做等,很常見的快捷鍵適用於許多應用。出色的鍵盤支援將會幫助您的應用實現更多的功能,一些應用甚至更進一步將高階功能放在使用者觸手可及的地方,比如使用者在使用 eDJing 應用時,只需按住 Ctrl 鍵就可以用觸控板搓碟。

如下展示了用於撤消的 Ctrl+Z 快捷鍵的程式碼,這部分程式碼類似於前面的 onKeyUp 和 onKeyDown 程式碼,但使用了 dispatchKeyShortcutEvent 來指示元鍵組合。請注意此時按下 Alt、Ctrl 或 Shift 鍵即可觸發此操作。完整程式碼如下所示:

override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean {
    return when (event.getKeyCode()) {
        KEYCODE_Z -> {
            undoAction() // [Ctrl]+z, [Shift]+z, 或 [Alt]+z 觸發
            true
        }
        else -> {
            super.dispatchKeyShortcutEvent(event)
        }
    }
}

如果您只希望響應特定的元鍵組合,可以使用 Meta_Alt_On,也可以使用類似 isShiftPressed() 或 isCtrlPressed() 的方法。完整程式碼如下所示:

when {
    event.isCtrlPressed && event.isShiftPressed -> {
        redoAction(); true // [Ctrl]+[Shift]+z 觸發
    }
    event.isCtrlPressed -> {
        undoAction(); true //[Ctrl]+z 觸發
    }
    else -> { // 交給系統處理
        super.dispatchKeyShortcutEvent(event)
    }
}

根據此處程式碼,只有在同時按下 Ctrl+Z 時才會執行撤消操作,同樣只有在同時按下 Ctrl+Shift+Z 時才會執行重做操作,並不會用到 Alt。

滑鼠/觸控板輸入支援

與鍵盤一樣,大多數滑鼠和觸控板輸入通常不需要任何額外的程式碼就可以工作。但開發者還是有必要使用滑鼠測試應用的所有功能,檢視是否有任何疏漏。

△ 滑鼠

△ 滑鼠

右鍵點選支援

右鍵點選是最常見的疏漏之一。觸控的一個常見範例是在螢幕上長按以執行基於上下文的操作,但長按滑鼠點選並不直觀。如果要支援右鍵點選,此處有幾種方案可供選擇。此處顯示了新增上下文選單的程式碼,完整程式碼如下所示:

registerForContextMenu(myView) 
// 首先為上下文選單註冊一個或多個檢視,這將自動處理長按和右鍵點選兩種操作。
...
override fun onCreateContextMenu(menu, view, menuInfo) {
    super.onCreateContextMenu(menu, view, menuInfo)
    menuInflater.inflater(R.menu.myContextMenu, menu)
    // 然後撤銷 overrideonCreateContextMenu 並擴充套件正確的選單佈局,同一選單可用於多個檢視。
}
override fun onCreateContextMenu(item: MenuItem): Boolean {
    return when(item.itemId){
        R.id.myMenuItemId -> { menuItemAction(); true }
        else -> { return super.onContextItemSelected(item) }
        // 最後,設定 onContextItemSelected 指示選中特定選單項時需要執行的操作。
    }
}

對於上下文選單之外的其他右鍵點選行為,可以用 onContextClickListener 設定檢視,只需使用它呼叫在長按用例中使用的相同方法即可。對應程式碼如下所示:

myView.setOnContextClickListener {
       performContextAction()
       true
}

懸停響應支援

使用者在使用滑鼠或觸控板時,通常希望介面能夠以某種方式做出響應。例如當滑鼠游標懸停在可點選的檢視上時會產生視覺反饋,如圖所示,可能是指標圖示發生了變化,又或者出現一些其他視覺指示,這些都可以被使用者直觀感受到。此處顯示了指標懸停在檢視上時的程式碼,完整程式碼如下所示:

myView.setOnHoverListener { view, motionEvent ->  //為檢視設定 onHoverListener
    when (motionEvent.action) {
        ACTION_HOVER_ENTER -> {
            view.pointerIcon = PointerIcon.getSystemIcon(
                appIicationContext, PointerIcon.TYPE_HAND
            )
            view.setBackgroundColor(Color.BLUE)
            true
        } // 監聽 HOVER_ENTER 事件並執行相應的操作。根據程式碼顯示指標圖示將變為手形且背景顏色將變為藍色。
        ACTION_HOVER_EXIT -> { resetUI(); }
        else -> { false }
        // 不要忘記設定當 HOVER_EXIT 發生時重置圖示和背景顏色。
    }
}

指標捕獲支援

指標捕獲是另一個常見的滑鼠和觸控板增強功能,不但對於一些遊戲至關重要,並且還可以為某些應用新增特定功能。應用能夠通過指標捕獲功能捕獲滑鼠游標,使游標不出現在螢幕上,這樣無需將游標移動到螢幕邊緣就可以接收相對的指標事件。像 Minecraft: 教育版等第一人稱視角遊戲就是很好的案例。

△ Minecraft: 教育版

△ Minecraft: 教育版

要支援指標捕獲,可以先呼叫 requestPointerCapture,然後再呼叫 releasePointerCapture 釋放捕獲的指標。在程式碼中可以新增 OnCapturedPointerListener 使用接收的指標資料,並利用指標位置的相對變化來實現一些很棒的功能。完整程式碼如下所示:

view.requestPointerCapture()
...
view.releasePointerCapture()
...
view.setOnCapturedPointerListener { _, motionEvent ->
    // 計算自從上次 motionEvent 事件後的座標增量
    mouseChangeX = motionEvent.x
    mouseChangey = motionEvent.y

    // 計算自從上次 motionEvent 事件後的位移
    val totalDistance = hypot(mouseChangeX, mouseChangeY)
    doSomethingCool(totalDistance)
}

手勢支援

此外 Android API 還提供了高階指標處理,可以新增手勢、雙指張合和縮放支援等,如下圖所示。

如果您希望瞭解更多 Android API 的相關資訊,請參閱 Android 開發者網站獲取入門指南——使用輕觸手勢

觸筆輸入支援

如果您已經在應用中新增對指標的出色支援,那麼對於大多數用例來說觸控筆通常能夠按預期正常工作。關於觸控筆的一些增強功能非常值得關注,比如部分裝置支援觸控筆傾斜和按壓,這有助於您在繪畫或繪圖應用新增一些出色的控制元件和功能。此外還有低延遲觸控筆 API 可讓您在繪畫或繪圖應用中獲得最低延遲的顯示響應,並提供可配置的描邊預測,為您打造用筆在紙上繪圖的體驗。如需瞭解實際效果,請在受支援的 Chromebook 或 Android 裝置上檢視類似於 Concepts 的應用。

△ Concepts 應用對觸控筆支援

△ Concepts 應用對觸控筆支援

  • 如需 瞭解實現細節,請參閱 Android 開發者網站有關 AXIS_PRESSURE 和 AXIS_TILT 的文件。

  • 低延遲觸控筆 API 庫和演示版應用,請參閱 GitHub

在 Android 模擬器中使用觸控筆

我們與 Microsoft 合作將主機觸控筆支援引入 Android 模擬器中,如果您正在優化應用以提供更高階的觸控筆支援,那麼您將可以在支援的主機上使用 Android 模擬器測試精確的傾斜和按壓控制。

Microsoft Surface Duo 開發者體驗團隊與 Google 合作開展了一項支援高階輸入開發和測試的工作,比如多點觸控分析和觸控筆支援。那麼在模擬器中執行應用時如何使用觸控筆測試應用?

△ 在模擬器中測試觸控筆

△ 在模擬器中測試觸控筆

如圖所示,顯示的是 Surface Studio 上執行的 Microsoft Duo 2 模擬器,此刻有兩款應用在同時執行: 右側窗格是示例應用,該示例允許您測試觸控筆按壓靈敏度、筆方向、擦除筆尖和其他觸控筆按鈕;左側窗格是 Microsoft OneNote 應用,使用模擬器可以在 OneNote 畫布上繪製、做筆記或擦除。

我們非常興奮,在支援觸控的 PC 上,Android 模擬器現在也可以支援多點觸控,這讓您可以測試需要使用多個手指的手勢與應用進行互動,比如雙指張合、縮放和其他觸控互動。

△ 在 Google 地圖中使用手勢操作

△ 在 Google 地圖中使用手勢操作

這款內建 Android Studio 的可摺疊模擬器正在執行 Google 地圖,只需使用兩個手指就可以放大和縮小地圖。而且這些模擬器更新的不僅是隻支援使用兩個手指,如果您的硬體允許,可以支援多達 10 個觸控點。

您看到的所有這些變化都不是 Surface Duo 模擬器所特有的,它們也適用於其他可摺疊模擬器。Microsoft 也一直在利用這些模擬器更新來開發和優化自己的應用,例如在包括 Surface Duo、大螢幕和其他可摺疊裝置等多種裝置型別上測試觸控筆的互動。

手柄輸入支援

如果您有一款遊戲應用則需要新增遊戲手柄支援。使用相應的鍵程式碼,確定要對 onKeyUp 還是 onKeyDown 執行操作。

△ 遊戲手柄

△ 遊戲手柄

遊戲手柄方向鍵與鍵盤箭頭鍵的鍵程式碼是相同的,只需監聽 KEYCODE_DPAD 事件即可同時處理這兩者。遊戲手柄按鈕也有自己的鍵程式碼,您可以監聽這些按鈕就像這裡為 X 按鈕進行的設定一樣。完整程式碼如下所示:

when (keyCode) {
    BUTTON_X -> {
        engageNitro(); return true
    }
    DPAD_UP, KEYCODE_W -> {
        goForward(); return true
    }
    DPAD_LEFT, KEYCODE_A -> {
        turnLeft(); return true
    }
    ...
}

MIDI 輸入支援

當涉及到專門的硬體時,需要針對裝置和用例提供支援。MIDI 支援對於音樂和創意工具來說尤其重要,它允許廣泛的、富有表現力的輸入訊號,從對壓力敏感的鋼琴鍵盤到具有滑塊、旋鈕、鍵盤等許多不同輸入觸發器的裝置,都能提供支援。

如果您希望使用或瞭解更多 MIDI 相關的資訊,Android Media Samples 庫中提供了一些便捷的開源示例,可以幫助您開始使用 MIDI。請檢視 MidiSynth 專案,特別是該專案中的 Synth Engine 模組。注意,從 Android 29 開始您還可以使用 NDK MIDI API

回顧

大螢幕的 Android 裝置已經出現而且愈發普及,在 Android 上提供出色的輸入支援一直很重要,而對於可摺疊裝置、平板電腦和 Chrome 作業系統來說尤為重要。請思考您應用的輸入處理以及如何增加互動、解鎖新功能並提升應用體驗。期待各位開發者投入精力構建精彩的 Android 應用,併為其添加了出色的輸入處理!

歡迎您 點選這裡 向我們提交反饋,或分享您喜歡的內容、發現的問題。您的反饋對我們非常重要,感謝您的支援!