大螢幕教戰手冊

Android 可以提供建構五星大螢幕應用程式的全部要件。這份教戰手冊的方案,挑選並結合了各種要件,可以解決特定開發問題。每個方案都包含最佳做法、優質程式碼範例以及逐步教學,可協助您成為大螢幕頂尖高手。

星級評等

方案是否妥善配合「大螢幕應用程式品質」指南,會成為我們給予星級評等的依據。

五星評等 符合 1 級標準,大螢幕表現脫穎而出
四星評等 符合 2 級標準,可以達到大螢幕最佳化
三星評等 符合 3 級標準,適用大螢幕
二星級評等 可提供部分大螢幕功能,但不符合大螢幕應用程式的品質指南
一星評等 符合特定用途需求,但無法妥善支援大螢幕

Chromebook 相機支援

三星評等

這在 Google Play 可吸引 Chromebook 使用者。

如果您的相機應用程式只能使用基本相機功能,請不要因為無意中指定了高階手機的進階相機功能,讓應用程式商店禁止 Chromebook 使用者安裝該應用程式。

Chromebook 內建前置相機 (朝向使用者),適合用於視訊會議、快照和其他應用程式。然而,並非所有 Chromebook 都有後置相機 (朝向外面),而且 Chromebook 上多數面向使用者的相機都不支援自動對焦或閃光燈。

最佳做法

無論相機設定為何,多功能相機應用程式都應適用所有裝置,包括備有前置鏡頭、後置鏡頭,以及 USB 外接鏡頭的裝置。

如要確保應用程式商店盡可能向更多裝置推薦您的應用程式,請務必聲明應用程式用到的所有相機功能,並明確指明這些功能是否必要。

要件

  • CAMERA 權限:允許應用程式存取裝置相機
  • <uses-feature> 資訊清單元素:向應用程式商店告知應用程式使用的功能
  • required 屬性:向應用程式商店指出,如果沒有指定功能,應用程式是否可正常運作

操作步驟

摘要

聲明 CAMERA 權限。請聲明可提供基本相機支援的相機功能,然後指定各項功能是否必要。

1. 聲明 CAMERA 權限

在應用程式資訊清單中新增下列權限:

<uses-permission android:name="android.permission.CAMERA" />
2. 聲明基本相機功能

在應用程式資訊清單中增列以下功能:

<uses-feature android:name="android.hardware.camera.any" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
3. 指定是否需要各項功能

android.hardware.camera.any 功能設定 android:required="false",允許具有任一種內建/外接鏡頭 (或根本沒有相機) 的裝置存取您的應用程式。

至於其他功能,請設定 android:required="false",確保 Chromebook 等沒有後置鏡頭、自動對焦或閃光燈功能的裝置,皆可在應用程式商店存取您的應用程式。

成果

Chromebook 使用者可以透過 Google Play 和其他應用程式商店下載及安裝您的應用程式。如果裝置支援完整相機功能 (例如手機),這些功能也不會受到限制。

明確設定應用程式支援的相機功能,並指定應用程式所需的功能,您就能夠盡量讓更多裝置使用您的應用程式。

其他資源

如需更多資訊,請參閱 <uses-feature> 說明文件中的「相機硬體功能」。

限制手機上應用程式的螢幕方向,而不限制大螢幕裝置的方向

二星級評等

您的應用程式在縱向模式作業出色,因此您已將應用程式設為僅限縱向顯示。然而您卻發現,在橫向的大螢幕上還能完成更多操作。

那麼,這兩者要如何兼顧呢?是否可以限制應用程式在小螢幕上以縱向模式顯示,但在大螢幕上啟用橫向模式?

最佳做法

最好的應用程式會尊重使用者的偏好,例如裝置的螢幕方向。

大螢幕應用程式品質」指南建議應用程式支援所有裝置設定,包括縱向和橫向模式、多視窗模式,以及摺疊式裝置摺疊與展開的狀態。應用程式應針對不同的設定來最佳化版面配置和使用者介面,並且在設定變更時儲存及還原狀態。

這個方案是暫時性措施,只能提供些微大螢幕支援。您可使用這個方案改善應用程式,直到能完整支援所有裝置設定。

要件

操作步驟

摘要

允許應用程式依照應用程式資訊清單,依預設處理螢幕方向變更。在執行階段中,決定應用程式視窗大小。如果應用程式視窗太小,請覆寫資訊清單方向設定,以限制應用程式的螢幕方向。

1. 指定應用程式資訊清單中的方向設定

您可以選擇避免宣告應用程式資訊清單的 screenOrientation 元素 (這種情況下,螢幕方向預設為 unspecified),或是將螢幕方向設為 fullUser。如果使用者尚未鎖定感應器旋轉功能,您的應用程式將支援所有裝置螢幕方向。

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

使用 unspecifiedfullUser 有細微但重要的差別。如果您未宣告 screenOrientation 值,系統會選擇螢幕方向,而系統用來定義螢幕方向的政策也會因裝置而異。另一方面,指定 fullUser 會更符合使用者為裝置定義的行為:如果使用者已鎖定感應器旋轉功能,應用程式會遵循使用者的偏好設定。否則,系統會允許使用四種螢幕方向,亦即直向、橫向、反向直向或反向橫向。請參閱「android:screenOrientation」。

2. 決定螢幕大小

在資訊清單中設定支援所有使用者允許的方向後,您就可以根據螢幕尺寸,以程式輔助的方式指定應用程式方向。

Jetpack WindowManager 程式庫新增至模組的 build.gradlebuild.gradle.kts 檔案:

Kotlin

implementation("androidx.window:window:version")
implementation("androidx.window:window-core:version")

Groovy

implementation 'androidx.window:window:version'
implementation 'androidx.window:window-core:version'

使用 Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics() 方法,即可取得 WindowMetrics 物件的裝置螢幕大小。您可以比較視窗指標與視窗大小類別,決定限制方向的時機。

Windows 大小類別提供小螢幕與大螢幕之間的中斷點。

請使用 WindowWidthSizeClass#COMPACTWindowHeightSizeClass#COMPACT 中斷點,判斷螢幕大小:

Kotlin

/** Determines whether the device has a compact screen. **/
fun compactScreen() : Boolean {
    val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this)
    val width = metrics.bounds.width()
    val height = metrics.bounds.height()
    val density = resources.displayMetrics.density
    val windowSizeClass = WindowSizeClass.compute(width/density, height/density)

    return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT ||
        windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT
}

Java

/** Determines whether the device has a compact screen. **/
private boolean compactScreen() {
    WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this);
    int width = metrics.getBounds().width();
    int height = metrics.getBounds().height();
    float density = getResources().getDisplayMetrics().density;
    WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density);
    return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT ||
                windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT;
}
    注意:
  • 上述範例是以活動的方法導入;因此,活動在 computeMaximumWindowMetrics() 引數中會被解除參照為 this
  • 使用 computeMaximumWindowMetrics() 方法代替 computeCurrentWindowMetrics(),因為應用程式可以透過多視窗模式啟動,而忽略螢幕方向設定。除非應用程式視窗即為整個裝置畫面,否則您無法判定應用程式視窗大小及覆寫方向設定。

請參閱「WindowManager」的操作說明,瞭解如何宣告依附元件,以便在應用程式中提供 computeMaximumWindowMetrics() 方法。

3. 覆寫應用程式資訊清單設定

如果您確定裝置螢幕為小尺寸,可以呼叫 Activity#setRequestedOrientation() 以覆寫資訊清單的 screenOrientation 設定:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    requestedOrientation = if (compactScreen())
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
        ActivityInfo.SCREEN_ORIENTATION_FULL_USER
    ...
    // Replace with a known container that you can safely add a
    // view to where the view won't affect the layout and the view
    // won't be replaced.
    val container: ViewGroup = binding.container

    // Add a utility view to the container to hook into
    // View.onConfigurationChanged. This is required for all
    // activities, even those that don't handle configuration
    // changes. You can't use Activity.onConfigurationChanged,
    // since there are situations where that won't be called when
    // the configuration changes. View.onConfigurationChanged is
    // called in those scenarios.
    container.addView(object : View(this) {
        override fun onConfigurationChanged(newConfig: Configuration?) {
            super.onConfigurationChanged(newConfig)
            requestedOrientation = if (compactScreen())
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
                ActivityInfo.SCREEN_ORIENTATION_FULL_USER
        }
    })
}

Java

@Override
protected void onCreate(Bundle savedInstance) {
    super.onCreate(savedInstanceState);
    if (compactScreen()) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    } else {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
    }
    ...
    // Replace with a known container that you can safely add a
    // view to where the view won't affect the layout and the view
    // won't be replaced.
    ViewGroup container = binding.container;

    // Add a utility view to the container to hook into
    // View.onConfigurationChanged. This is required for all
    // activities, even those that don't handle configuration
    // changes. You can't use Activity.onConfigurationChanged,
    // since there are situations where that won't be called when
    // the configuration changes. View.onConfigurationChanged is
    // called in those scenarios.
    container.addView(new View(this) {
        @Override
        protected void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (compactScreen()) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
            }
        }
    });
}

只要將邏輯新增至 onCreate()View.onConfigurationChanged() 方法中,即可在每次調整活動大小,或活動在螢幕間移動時 (例如裝置旋轉,或摺疊式裝置摺疊/展開後),取得最大視窗指標並覆寫螢幕方向設定。如要進一步瞭解發生設定變更的時間,以及導致活動重新建立的時間,請參閱「處理設定變更」。

成果

現在即使裝置旋轉時,您的應用程式仍應在小螢幕上以縱向顯示。在大螢幕上,應用程式應支援橫向和縱向。

其他資源

如要瞭解如何升級應用程式來一律支援所有裝置設定,請參閱以下內容:

使用外接鍵盤的空格鍵暫停及繼續播放媒體

四星評等

處理外部鍵盤輸入內容的功能,也是大螢幕最佳化作業的一環,例如決定按下空格鍵來暫停或繼續播放影片/其他媒體後,要對此事件做出什麼回應。這對平板電腦和 Chromebook 特別有用,因為前者往往連接外部鍵盤,而後者通常隨附外接鍵盤,但可在平板電腦模式下使用。

如果媒體是視窗中的唯一元素,例如播放全螢幕影片時,請在活動層級回應按鍵事件 (在 Jetpack Compose 中,則在畫面層級做出回應)。

最佳做法

每當應用程式播放媒體檔案時,使用者應該只需按下實體鍵盤上的空格鍵,就能暫停並繼續播放。

要件

Compose

  • onPreviewKeyEvent:這個 Modifier 可讓元件 (或其中一個子項) 在成為焦點時,攔截硬體的按鍵事件。
  • onKeyEvent:與 onPreviewKeyEvent 類似,這個 Modifier 可讓元件 (或其中一個子項) 在成為焦點時,攔截硬體的按鍵事件。

Views

  • onKeyUp():在按鍵鬆開,且非由活動中的檢視畫面處理時呼叫。

操作步驟

摘要

以 Jetpack Compose 為基礎和以 View 為基礎的應用程式,會用類似的方式回應按下鍵盤按鍵的事件:應用程式必須監聽按鍵事件、篩選事件,以及回應特定的按鍵事件 (例如按下空格鍵的事件)。

1. 監聽鍵盤事件

Views

在應用程式的活動中,覆寫 onKeyUp() 方法:

Kotlin

override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    ...
}

Java

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    ...
}

每當按下的按鍵鬆開時,系統都會叫用此方法,因此每次按下按鍵都恰好會觸發一次。

Compose

透過 Jetpack Compose,您可以在管理按鍵操作的畫面內使用 onPreviewKeyEventonKeyEvent 修飾符:

Column(modifier = Modifier.onPreviewKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp) {
        ...
    }
    ...
})

Column(modifier = Modifier.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp) {
        ...
    }
    ...
})

2. 篩選按壓空格鍵的事件

onKeyUp() 方法或 Compose 的 onPreviewKeyEventonKeyEvent 修飾符方法中篩選 KeyEvent.KEYCODE_SPACE,即可將正確的事件傳送給媒體元件:

Views

Kotlin

if (keyCode == KeyEvent.KEYCODE_SPACE) {
    togglePlayback()
    return true
}
return false

Java

if (keyCode == KeyEvent.KEYCODE_SPACE) {
    togglePlayback();
    return true;
}
return false;

Compose

Column(modifier = Modifier.onPreviewKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
        ...
    }
    ...
})

Column(modifier = Modifier.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
        ...
    }
    ...
})

成果

對於按下空格鍵來暫停並繼續播放影片/其他媒體這類事件,您的應用程式現在可以做出回應。

其他資源

如要進一步瞭解鍵盤事件及其管理方式,請參閱「處理鍵盤輸入」。

防止誤觸觸控筆

五星級評等

在大螢幕上,觸控筆是特別能協助使用者提高工作效率和激發創意的工具。不過,當他們使用觸控筆繪圖、書寫或與應用程式互動時,有時手掌會碰到螢幕。在系統將這類事件辨別為手掌誤觸,並加以忽略之前,可能就會先將觸控事件回報給您的應用程式。

最佳做法

您的應用程式必須辨識並忽略不必要的觸控事件。藉由調度 MotionEvent 物件,Android 會取消手掌觸碰事件。您可以檢查 ACTION_CANCELACTION_POINTER_UPFLAG_CANCELED 的物件,判斷是否要拒絕手掌觸碰引發的手勢。

要件

  • MotionEvent:代表觸控和動作事件,包含判斷是否應忽略事件所需的資訊。
  • OnTouchListener#onTouch():接收 MotionEvent 物件。
  • MotionEvent#getActionMasked():傳回與動作事件相關聯的動作。
  • ACTION_CANCELMotionEvent 常數,表示應取消手勢。
  • ACTION_POINTER_UPMotionEvent 常數,表示第一個指標以外的指標已上移 (也就是已放棄與裝置螢幕接觸)。
  • FLAG_CANCELEDMotionEvent 常數,表示指標上移是無意間的觸控事件所致。已在 Android 13 (API 級別 33) 以上版本加入 ACTION_POINTER_UPACTION_CANCEL 事件中。

操作步驟

摘要

檢查調度給應用程式的 MotionEvent 物件。請使用 MotionEvent API 判斷事件特性:

  • 單指標事件 - 檢查 ACTION_CANCEL。如果是 Android 13 以上版本,請一併檢查 FLAG_CANCELED
  • 多指標事件 - 在 Android 13 以上版本中,檢查 ACTION_POINTER_UPFLAG_CANCELED

回應 ACTION_CANCELACTION_POINTER_UP/FLAG_CANCELED 事件。

1. 取得動作事件物件

在應用程式中新增 OnTouchListener

Kotlin

val myView = findViewById<View>(R.id.myView).apply {
    setOnTouchListener { view, event ->
        // Process motion event.
    }
}

Java

View myView = findViewById(R.id.myView);
myView.setOnTouchListener( (view, event) -> {
    // Process motion event.
});
2. 判斷事件動作和標記

檢查是否有 ACTION_CANCEL,這表示所有 API 級別上的單指標事件。如果是 Android 13 以上版本,請檢查 ACTION_POINTER_UP 是否有 FLAG_CANCELED.

Kotlin

val myView = findViewById<View>(R.id.myView).apply {
    setOnTouchListener { view, event ->
        when (event.actionMasked) {
            MotionEvent.ACTION_CANCEL -> {
                //Process canceled single-pointer motion event for all SDK versions.
            }
            MotionEvent.ACTION_POINTER_UP -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
                   (event.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) {
                    //Process canceled multi-pointer motion event for Android 13 and higher.
                }
            }
        }
        true
    }
}

Java

View myView = findViewById(R.id.myView);
myView.setOnTouchListener( (view, event) -> {
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_CANCEL:
            // Process canceled single-pointer motion event for all SDK versions.
        case MotionEvent.ACTION_UP:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
               (event.getFlags() & MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) {
                //Process canceled multi-pointer motion event for Android 13 and higher.
            }
    }
    return true;
});
3. 取消手勢

辨識出手掌觸碰事件後,您可以取消手勢在螢幕上引發的操作。

您的應用程式必須保留使用者動作記錄,以便在有手掌觸碰這類情形發生時,取消這些無意的輸入操作。如需範例,請參閱「強化 Android 應用程式中的觸控筆支援」程式碼研究室中的「實作基本繪圖應用程式」。

成果

您的應用程式現在可以辨別並拒絕多指標事件 (在 Android 13 以上的 API 級別上) 和單指標事件 (在所有 API 級別上) 的手掌觸碰操作了。

其他資源

如需更多資訊,請參考下列資源:

WebView 狀態管理

三星評等

WebView 是一種常用的元件,可提供狀態管理所需的進階系統。WebView 必須在遇到各種設定變更時維持自身狀態和捲動位置。否則,當使用者旋轉裝置或展開摺疊式手機時,WebView 的捲動位置就可能遺失,進而強迫使用者從 WebView 頂端再次捲動至上一個捲動位置。

最佳做法

請盡量減少重新建立 WebView 的次數。WebView 很適合管理自身狀態,您只要盡可能管理設定變更,即可善用這項特質。應用程式之所以必須處理設定變更,是因為 Activity 重建作業 (系統處理設定變更的方式) 也會重新建立 WebView,導致 WebView 狀態遺失。

要件

  • android:configChanges:資訊清單 <activity> 元素的屬性,可列出活動處理的設定變更。
  • View#invalidate():導致重新繪製檢視畫面的方法,由 WebView 繼承。

操作步驟

摘要

如要儲存 WebView 狀態,請盡可能避免重建 Activity,然後您需將 WebView 作廢,使其可以調整大小,同時保留自身狀態。

1. 在應用程式的 AndroidManifest.xml 檔案中加入設定變更

指定應用程式 (而非系統) 處理的設定變更,避免重新建立活動:

<activity
  android:name=".MyActivity"
  android:configChanges="screenLayout|orientation|screenSize
      |keyboard|keyboardHidden|smallestScreenSize" />

2. 在應用程式收到設定變更時將 WebView 作廢

Kotlin

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    webView.invalidate()
}

Java

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    webview.invalidate();
}

這個步驟僅適用於 View 系統,因為 Jetpack Compose 不需要將任何內容作廢,即可正確調整 Composable 元素大小。不過,如果管理方式不當,Compose 往往會重新建立 WebView。此時不妨使用 Accompanist WebView 包裝函式在 Compose 應用程式中儲存及還原 WebView 狀態。

成果

應用程式的 WebView 元件現在會在遇到多種設定變更 (舉凡從調整大小、變更螢幕方向、到折疊和展開) 時保留自身狀態和捲動位置。

其他資源

如要進一步瞭解設定變更及其管理方式,請參閱「處理設定變更」。

RecyclerView 狀態管理

三星評等

RecyclerView 可利用極少量圖像資源顯示大量資料。當 RecyclerView 捲動瀏覽 RecyclerView 項目清單時,會重複使用捲動至螢幕外項目的 View 執行個體,以在螢幕上捲動時建立新項目。不過,設定變更 (例如裝置旋轉) 可能會重設 RecyclerView 的狀態,導致使用者必須再次捲動回 RecyclerView 項目清單中的先前位置。

最佳做法

每當設定變更時,RecyclerView 都應維持原本的狀態 (尤其是捲動位置),清單元素的狀態也不應變動。

要件

操作步驟

摘要

設定 RecyclerView.Adapter 的狀態還原政策,儲存 RecyclerView 捲動位置。接著儲存 RecyclerView 清單項目的狀態。然後將清單項目的狀態新增至 RecyclerView 轉接程式,並在清單項目繫結至 ViewHolder 時還原清單項目狀態。

1. 啟用 Adapter 狀態還原政策

啟用 RecyclerView 轉接程式的狀態還原政策,以便在任何設定變更時保留 RecyclerView 的捲動位置。請將政策規格新增至轉接程式建構函式:

Kotlin

class MyAdapter() : RecyclerView.Adapter() {
    init {
        stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
    }
    ...
}

Java

class MyAdapter extends RecyclerView.Adapter {

    public Adapter() {
        setStateRestorationPolicy(StateRestorationPolicy.PREVENT_WHEN_EMPTY);
    }
    ...
}

2. 儲存有狀態清單項目的狀態

儲存複雜 RecyclerView 清單項目的狀態,例如包含 EditText 元素的項目。舉例來說,如要儲存 EditText 的狀態,請新增與 onClick 處理常式類似的回呼,以擷取文字變更。然後在回呼中,定義要儲存的資料:

Kotlin

input.addTextChangedListener(
    afterTextChanged = { text ->
        text?.let {
            // Save state here.
        }
    }
)

Java

input.addTextChangedListener(new TextWatcher() {
    
    ...

    @Override
    public void afterTextChanged(Editable s) {
        // Save state here.
    }
});

ActivityFragment 中宣告回呼。使用 ViewModel 儲存狀態。

3. 將清單項目狀態新增至 Adapter

將清單項目的狀態新增至 RecyclerView.Adapter。請在主機 ActivityFragment 建立時,將項目狀態傳遞至轉接程式建構函式:

Kotlin

val adapter = MyAdapter(items, viewModel.retrieveState())

Java

MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState());

4. 在轉接程式的 ViewHolder 中復原清單項目狀態

RecyclerView.Adapter 中,如果您將 ViewHolder 繫結至項目,請還原該項目的狀態:

Kotlin

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    ...
    val item = items[position]
    val state = states.firstOrNull { it.item == item }

    if (state != null) {
        holder.restore(state)
    }
}

Java

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    ...
    Item item = items[position];
    Arrays.stream(states).filter(state -> state.item == item)
        .findFirst()
        .ifPresent(state -> holder.restore(state));
}

成果

RecyclerView 現在可以還原其捲動位置,以及 RecyclerView 清單中各項目的狀態。

其他資源

卸除式鍵盤管理

三星評等

支援卸離式鍵盤,有助提高使用者在大螢幕裝置上的工作效率。每次將鍵盤連接至裝置或從裝置卸離時,Android 都會觸發設定變更,這可能會導致 UI 狀態遺失。應用程式可以儲存及還原其狀態,讓系統處理活動重建作業,或針對鍵盤設定變更限制活動重建。在所有情況下,與鍵盤相關的所有資料都會儲存在 Configuration 物件中。設定物件的 keyboardkeyboardHidden 欄位包含鍵盤類型及其可用性的相關資訊。

最佳做法

針對大螢幕最佳化的應用程式可支援各種類型的輸入裝置,包括軟體和硬體鍵盤、觸控筆、滑鼠、觸控板和其他週邊裝置。

支援外部鍵盤涉及設定變更,您可以透過以下兩種方式管理設定:

  1. 讓系統重新建立目前執行中的活動,讓您自行管理應用程式的狀態。
  2. 自行管理設定變更 (系統不會重新建立活動):
    • 宣告所有與鍵盤相關的設定值
    • 建立設定變更處理常式

效率提升應用程式通常需要精確控製文字輸入和其他輸入的 UI,因此可因自行處理設定變更而受益。

在特殊情況下,建議您在附加或卸離實體鍵盤時變更應用程式版面配置,例如為工具或編輯視窗取得更多空間。

由於監聽設定變更的唯一可靠方法,就是覆寫檢視畫面的 onConfigurationChanged() 方法,因此您可以在應用程式活動中新增 View 例項,並在檢視畫面的 onConfigurationChanged() 處理常式中回應連接或卸離鍵盤造成的設定變更。

要件

  • android:configChanges:應用程式資訊清單 <activity> 元素的屬性,通知系統應用程式管理的設定變更。
  • View#onConfigurationChanged():用於回應新應用程式設定的方法。

操作步驟

摘要

宣告 configChanges 屬性並新增鍵盤相關值。將 View 加入活動的檢視區塊階層,並監聽設定變更。

1. 聲明 configChanges 屬性

keyboard|keyboardHidden 值新增至受管理的設定變更清單,藉此更新應用程式資訊清單中的 <activity> 元素:

<activity
      …
      android:configChanges="...|keyboard|keyboardHidden">

2. 在檢視區塊階層中新增空白資料檢視

宣告新的檢視畫面,並在檢視區塊的 onConfigurationChanged() 方法中加入處理常式程式碼:

Kotlin

val v = object : View(this) {
  override fun onConfigurationChanged(newConfig: Configuration?) {
    super.onConfigurationChanged(newConfig)
    // Handler code here.
  }
}

Java

View v = new View(this) {
    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Handler code here.
    }
};

成果

您的應用程式現在會回應連接或卸離的外接鍵盤,而不會重新建立目前執行的活動。

其他資源

如要瞭解如何在設定變更 (例如鍵盤附件或卸離) 時儲存應用程式的 UI 狀態,請參閱「儲存 UI 狀態」。