支援三折式裝置和橫向折疊式裝置

橫向摺疊式手機處於闔上和完全展開狀態,旁邊是處於闔上和完全展開狀態的三摺式手機。

開發人員為摺疊式裝置建立應用程式時,經常會遇到獨特的困難,尤其是 Samsung Trifold 或原始 Pixel Fold 等裝置,這類裝置會以橫向格式開啟 (rotation_0 = landscape)。開發人員的錯誤包括:

  • 對裝置螢幕方向的假設有誤
  • 容易忽略的用途
  • 無法在設定變更時重新計算或快取值

裝置相關問題包括:

  • 封面螢幕和內螢幕的裝置自然方向不一致 (根據 rotation_0 = 直向的假設),導致應用程式在折疊和展開過程中失敗
  • 螢幕密度不同,以及 density 設定變更處理方式有誤
  • 相機感應器依賴自然方向,導致相機預覽畫面發生問題

如要在摺疊式裝置上提供優質使用者體驗,請著重於下列重要領域:

  • 根據應用程式占用的實際螢幕區域判斷應用程式的方向,而非裝置的實體方向
  • 更新相機預覽畫面,正確管理裝置方向和顯示比例,避免預覽畫面方向有誤,並防止圖片遭到延展或裁剪
  • 在裝置折疊或展開時,透過保留狀態 (使用 ViewModel 或類似方法),或手動處理螢幕密度和方向變更,維持應用程式連續性,避免應用程式重新啟動或狀態遺失
  • 如果應用程式使用動作感應器,請調整座標系統,使其與螢幕目前的螢幕方向一致,並避免根據 rotation_0 = 直向做出假設,確保使用者互動精確無誤。

建構自動調整式版面配置

如果應用程式已自動調整,並符合「大螢幕應用程式品質」指南中規定的最佳化等級 (第 2 級),應用程式應可在摺疊式裝置上正常運作。否則,請先查看下列 Android 基礎適應性開發概念,再仔細檢查三摺式和橫向摺疊式裝置的具體詳細資料。

自動調整式版面配置

您的 UI 不僅要處理不同螢幕大小,還必須處理顯示比例的即時變化,例如展開裝置、進入多視窗或電腦視窗模式。如需進一步瞭解如何執行下列操作,請參閱「關於自動調整式版面配置」:

  • 設計及實作自動調整式版面配置
  • 根據視窗大小調整應用程式的主要導覽
  • 使用視窗大小類別調整應用程式 UI
  • 使用 Jetpack API 簡化標準版面配置 (例如清單/詳細資料) 的實作程序
在開啟的摺疊式裝置上,應用程式會顯示上下黑邊;在另一個開啟的摺疊式裝置上,同一應用程式則會以全螢幕顯示,並採用自適應版面配置。
圖 1. 非自動調整 (有上下黑邊) 和自動調整版面配置的差異。

視窗大小類別

摺疊式裝置 (包括橫向摺疊式裝置和三摺式裝置) 可立即在精簡、中等和展開視窗大小類別之間切換。瞭解並實作這些類別,可確保應用程式根據目前的裝置狀態顯示正確的導覽元件和內容密度。

應用程式在精簡、中等和展開視窗大小類別的裝置上顯示。
圖 2. 視窗大小類別。

以下範例使用 Material 3 適應性程式庫,先叫用 currentWindowAdaptiveInfo() 函式,然後針對三種視窗大小類別使用對應的版面配置,判斷應用程式可用的空間大小:

val adaptiveInfo = currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)
val windowSizeClass = adaptiveInfo.windowSizeClass

when {
  windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND) -> // Large
  windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND) -> // Medium
  else -> // Compact
}

詳情請參閱「使用視窗大小類別」。

大型螢幕應用程式品質指南

遵守「大螢幕應用程式品質」指南的第 2 級 (大螢幕最佳化)第 1 級 (大螢幕差異化),可確保應用程式在三摺裝置、橫向折疊式裝置和其他大螢幕裝置上提供優質的使用者體驗。這些指南涵蓋多個層級的重要檢查,可協助您從準備好自動調整,進而提供差異化的體驗。

Android 16 以上版本

如果應用程式指定 Android 16 (API 級別 36) 以上版本,系統會忽略最小寬度 >= 600 dp 的螢幕方向、大小調整和螢幕比例限制。應用程式會填滿整個顯示視窗,無論長寬比或使用者偏好的螢幕方向為何,且不再使用加上黑邊的相容模式。

特殊注意事項

三摺機和橫向摺疊機的硬體行為獨特,因此需要特別處理,尤其是感應器、相機預覽畫面和設定連續性 (摺疊、展開或調整大小時保留狀態)。

相機預覽

在橫向摺疊式裝置或顯示比例計算 (例如多視窗、桌面視窗或連線螢幕) 中,常見的問題是相機預覽畫面出現延展、側向、裁剪或旋轉的情況。

假設不相符

在大螢幕和折疊式裝置上,應用程式可能會假設相機功能 (例如顯示比例和感應器方向) 與裝置功能 (例如裝置方向和自然方向) 之間存在固定關係,因此經常發生這個問題。

新的外型規格挑戰了這項假設。折疊式裝置可以變更螢幕大小和顯示比例,不必旋轉裝置。舉例來說,展開裝置會改變螢幕比例,但如果使用者沒有旋轉裝置,裝置的旋轉角度就不會改變。如果應用程式假設長寬比與裝置旋轉方向相關,可能會錯誤旋轉或縮放相機預覽畫面。如果應用程式假設相機感應器方向與直向裝置方向一致,也可能發生這種情況,但這不一定適用於橫向摺疊裝置。

解決方案 1:Jetpack CameraX (最佳)

最簡單且最穩健的解決方案是使用 Jetpack CameraX 程式庫。其 PreviewView UI 元素可自動處理所有預覽複雜度:

  • PreviewView 正確調整感應器方向、裝置旋轉和縮放比例。
  • 這項功能會維持攝影機影像的長寬比,通常是透過置中和裁剪 (FILL_CENTER) 達成。
  • 如需去信箱預覽,您可以將調整類型設為 FIT_CENTER

詳情請參閱 CameraX 說明文件中的「實作預覽」。

解決方案 2:CameraViewfinder

如果您使用現有的 Camera2 程式碼集,CameraViewfinder 程式庫 (可回溯相容於 API 級別 21) 也是另一種現代解決方案。它會使用 TextureViewSurfaceView,並為您套用所有必要轉換 (長寬比、縮放和旋轉),簡化攝影機串流的顯示方式。

詳情請參閱「CameraViewfinder 介紹」網誌文章和「相機預覽」開發人員指南。

解決方案 3:手動實作 Camera2

如果無法使用 CameraX 或 CameraViewfinder,您必須手動計算方向和長寬比,並確保每次設定變更時都會更新計算結果:

  • CameraCharacteristics 取得相機感應器方向 (例如 0、90、180、270 度)。
  • 取得裝置目前的螢幕旋轉角度 (例如 0、90、180、270 度)。
  • 使用這兩個值,判斷 SurfaceViewTextureView 的必要轉換。
  • 請確保輸出內容的顯示比例 Surface 與相機預覽畫面一致,以免畫面扭曲。
  • 相機應用程式可能會在部分畫面上執行,無論是多視窗模式、電腦視窗模式,還是連線螢幕都一樣。因此,螢幕大小不應用於判斷相機觀景窗的尺寸,請改用視窗指標

詳情請參閱「相機預覽」開發人員指南和「在不同板型規格上使用相機應用程式」影片。

解決方案 4:使用意圖執行基本相機動作

如果不需要太多相機功能,簡單明瞭的解決方案是執行基本相機動作,例如使用裝置的預設相機應用程式拍攝相片或影片。您不需要整合相機程式庫,而是使用 Intent

詳情請參閱「相機意圖」。

設定和連貫性

折疊式裝置可提升 UI 多功能性,但可能比非折疊式裝置啟動更多設定變更。應用程式必須管理這些設定變更及其組合,例如裝置旋轉、摺疊/展開,以及在多視窗或電腦模式下調整視窗大小,同時保留或還原應用程式狀態。舉例來說,應用程式必須維持下列連續性:

  • 應用程式狀態,不會導致當機或對使用者造成干擾 (例如切換畫面或將應用程式傳送至背景時)
  • 可捲動欄位的捲軸位置
  • 在文字欄位中輸入的文字和鍵盤狀態
  • 媒體播放位置,以便在啟動設定變更後,從上次中斷的位置繼續播放

經常觸發的設定變更包括 screenSizesmallestScreenSizescreenLayoutorientationdensityfontScaletouchscreenkeyboard

請參閱 android:configChanges 和「處理設定變更」。如要進一步瞭解如何管理應用程式狀態,請參閱「儲存 UI 狀態」。

密集度設定變更

三折式和橫向折疊式裝置的內外螢幕可能具有不同的像素密度。因此,管理 density 的設定變更時,請特別留意。顯示密度變更時,Android 通常會重新啟動活動,這可能會導致資料遺失。如要避免系統重新啟動活動,請在資訊清單中宣告密度處理方式,並在應用程式中以程式輔助方式管理設定變更。

AndroidManifest.xml 設定

  • density:宣告應用程式將處理螢幕密度變更
  • 其他設定變更:建議您也宣告其他經常發生的設定變更,例如 screenSizeorientationkeyboardHiddenfontScale

宣告密度 (和其他設定變更) 可避免系統重新啟動活動,並改為呼叫 onConfigurationChanged()。

實作 onConfigurationChanged()

發生密度變更時,您必須在回呼中更新資源 (例如重新載入點陣圖或重新計算版面配置大小):

  • 確認 DPI 已變更為 newConfig.densityDpi
  • 將自訂檢視區塊、自訂可繪項目等重設為新的密度

要處理的資源項目

  • 圖片資源:以特定密度的資源取代點陣圖和可繪項目,或直接調整比例
  • 版面配置單位 (dp 到 px 的轉換):重新計算檢視畫面大小、邊界、邊框間距
  • 字型和文字大小:重新套用 sp 單位文字大小
  • 自訂 View/Canvas 繪圖:更新用於繪圖的像素值 Canvas

判斷應用程式方向

建構自動調整式應用程式時,請勿依賴實體裝置旋轉,因為大螢幕裝置會忽略這項設定,且多視窗模式下的應用程式方向可能與裝置不同。請改用 Configuration.orientation 或 WindowMetrics,根據視窗大小判斷應用程式目前是否為橫向或直向。

解決方案 1:使用 Configuration.orientation

這項屬性會識別應用程式目前顯示的方向。

解決方案 2:使用 WindowMetrics#getBounds()

您可以取得應用程式目前的顯示邊界,並檢查其寬度和高度,以判斷方向。

如要限制手機 (或摺疊裝置外螢幕) 的應用程式方向,但不限制大螢幕裝置的方向,請參閱「限制手機螢幕的方向」。

姿勢和顯示模式

直向和橫向折疊式裝置都支援桌面和 HALF_OPENED 等折疊型態與狀態。不過,摺疊機不支援立架模式,無法使用 HALF_OPENED。三摺機則提供更大的螢幕,完全展開時可帶來獨特的使用者體驗。

如要在支援 HALF_OPENED 的摺疊式裝置上區分應用程式,請使用 Jetpack WindowManager API,例如 FoldingFeature

如要進一步瞭解摺疊式裝置的姿勢、狀態,以及相機預覽畫面支援,請參閱下列開發人員指南:

摺疊式裝置提供獨特的檢視體驗。透過後置顯示模式和雙螢幕模式,您可以為摺疊式裝置打造獨特的顯示功能,例如後置鏡頭自拍預覽,以及在內外螢幕同時顯示不同畫面。詳情請參閱:

將螢幕方向鎖定為自然感應器方向

如果是非常特殊的用途 (特別是需要接管整個螢幕的應用程式,與裝置的摺疊狀態無關),nosensor 旗標可讓您將應用程式鎖定在裝置的自然方向。舉例來說,Pixel Fold 摺疊時的自然方向為直向,展開時則為橫向。新增 nosensor 標記後,應用程式在外螢幕上執行時會強制鎖定為直向模式,在內螢幕上執行時則會鎖定為橫向模式。

<activity
  android:name=".MainActivity"
  android:screenOrientation="nosensor">

遊戲和 XR 感應器重新對應

對於遊戲和 XR 應用程式,系統會以裝置固定的座標系統提供原始感應器資料 (例如陀螺儀或加速計)。如果使用者旋轉裝置,以橫向模式玩遊戲,感應器軸不會隨著螢幕旋轉,導致遊戲控制項不正確。

如要修正這個問題,請檢查目前的 Display.getRotation(),然後據此重新對應軸:

  • 旋轉 0:x=x,y=y
  • 旋轉 90 度:x=-y,y=x
  • 旋轉 180 度:x=-x, y=-y
  • 旋轉 270 度:x=y,y=-x

如果是用於指南針或 XR 應用程式的旋轉向量,請使用 SensorManager.remapCoordinateSystem(),根據目前的旋轉情形,將鏡頭方向或螢幕頂端對應至新軸。

應用程式相容性

應用程式必須遵守應用程式品質指南,確保與所有板型規格和連線螢幕相容。如果應用程式無法遵守這些規範,裝置製造商可以實作相容性處理方式,但這可能會降低使用者體驗。

如需更多資訊,請參閱平台提供的相容性解決方法完整清單,特別是與相機預覽覆寫可能改變應用程式行為的 Android 16 API 變更相關的解決方法。

如要進一步瞭解如何建構自動調整型應用程式,請參閱「大螢幕應用程式品質」。