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

左側為闔上和完全展開的橫向摺疊式手機,右側為闔上和完全展開的三摺式手機。

為摺疊式裝置建立應用程式時,開發人員經常會遇到獨特的困難,尤其是 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()
val windowSizeClass = adaptiveInfo.windowSizeClass

when {
  windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND) -> // Expanded
  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 執行基本相機動作

如果不需要太多相機功能,簡單的解決方案是執行基本相機操作,例如使用裝置的預設相機應用程式拍攝相片或影片。您不需要整合相機程式庫,而是使用 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 變更相關的解決方法。

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