您需要各種資訊 (例如裝置功能和應用程式狀態),才能更新應用程式版面配置。視窗寬度和高度是最常用的資訊。此外,您也可以參考下列資訊:
- 窗戶姿勢
- 指標裝置精確度
- 鍵盤類型
- 裝置是否支援攝影機和麥克風
- 使用者與裝置螢幕之間的距離
由於資訊會動態更新,因此您需要監控資訊,並在發生任何更新時觸發重組。mediaQuery 函式會抽象化資訊檢索的詳細資料,讓您專注於定義觸發版面配置更新的條件。以下範例會在摺疊式裝置處於桌面模式時,將版面配置切換為 TabletopLayout:
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
啟用 mediaQuery 函式
如要啟用 mediaQuery 函式,請將 ComposeUiFlags 物件的 isMediaQueryIntegrationEnabled 屬性設為 true:
class MyApplication : Application() { override fun onCreate() { ComposeUiFlags.isMediaQueryIntegrationEnabled = true super.onCreate() } }
定義含參數的條件
您可以將條件定義為在 UiMediaScope 中評估的 lambda。mediaQuery 函式會根據目前狀態和裝置功能評估條件。函式會傳回布林值,因此您可以使用條件分支 (例如 if 運算式) 判斷版面配置。表 1 說明 UiMediaScope 中可用的參數。
| 參數 | 值類型 | 說明 |
|---|---|---|
windowWidth |
Dp |
目前的視窗寬度 (以 dp 為單位)。 |
windowHeight |
Dp |
目前的視窗高度 (以 dp 為單位)。 |
windowPosture |
UiMediaScope.Posture |
應用程式視窗的目前姿勢。 |
pointerPrecision |
UiMediaScope.PointerPrecision |
可用指標裝置的最高精確度。 |
keyboardKind |
UiMediaScope.KeyboardKind |
可用的鍵盤類型或已連線的鍵盤。 |
hasCamera |
Boolean |
裝置是否支援相機。 |
hasMicrophone |
Boolean |
裝置是否支援麥克風。 |
viewingDistance |
UiMediaScope.ViewingDistance |
使用者與裝置螢幕之間的典型距離。 |
UiMediaScope 物件會解析參數的值。
mediaQuery 函式會使用 LocalUiMediaScope.current 存取 UiMediaScope 物件,該物件代表目前的裝置功能和環境。進行任何變更時,這個物件都會動態更新,例如使用者變更裝置姿勢時。接著,mediaQuery 函式會使用更新後的 UiMediaScope 物件評估 query lambda,並傳回布林值。舉例來說,下列程式碼片段會根據 windowPosture 參數值,在 TabletopLayout 和 FlatLayout 之間選擇。
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
根據視窗大小做出決定
視窗大小類別是一組自主的可視區域中斷點,有助於設計、開發及測試自動調整式版面配置。您可以比較代表目前視窗大小的兩個參數,以及視窗大小類別中定義的門檻。以下範例會根據視窗寬度變更窗格數量。WindowSizeClass 類別具有視窗大小類別的閾值常數 (圖 1)。
derivedMediaQuery 函式會評估 query lambda,並將結果包裝在 derivedStateOf 中。由於 windowWidth 和 windowHeight 可能經常更新,因此在 query lambda 中參照這些參數時,請呼叫 derivedMediaQuery 函式,而不是 mediaQuery 函式。
val narrowerThanMedium by derivedMediaQuery { windowWidth < WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND.dp } val narrowerThanExpanded by derivedMediaQuery { windowWidth < WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND.dp } when { narrowerThanMedium -> SinglePaneLayout() narrowerThanExpanded -> TwoPaneLayout() else -> ThreePaneLayout() }
根據視窗姿勢更新版面配置
windowPosture 參數會以 UiMediaScope.Posture 物件的形式,描述目前的視窗姿勢。您可以比較參數與 UiMediaScope.Posture 類別中定義的值,檢查目前的姿勢。以下範例會根據視窗姿勢切換版面配置:
when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() }
檢查可用指標裝置的精確度
高精確度指標裝置可協助使用者精確指向 UI 元素。 指標裝置的精確度取決於裝置類型。
pointerPrecision 參數說明可用指標裝置 (例如滑鼠和觸控螢幕) 的精確度。UiMediaScope.PointerPrecision 類別中定義了四個值:Fine、Coarse、Blunt 和 None。
None 表示沒有可用的指標裝置。
精確度由高到低依序為:Fine、Coarse 和 Blunt。
如果有多個指標裝置可用,且精確度不同,系統會以精確度最高的裝置解析參數。舉例來說,假設有兩個指標裝置 (Fine 精確裝置和 Blunt 精確裝置),則 Fine 是 pointerPrecision 參數的值。
以下範例顯示使用者使用低精確度指標裝置時,按鈕會變大:
if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Blunt }) { LargeSizeButton() } else { NormalSizeButton() }
查看可用的鍵盤類型
keyboardKind 參數代表可用鍵盤的類型:Physical、Virtual 和 None。如果顯示螢幕小鍵盤,且同時有硬體鍵盤可用,參數會解析為 Physical。如果系統偵測不到這兩者,參數值就是 None。
以下範例顯示的訊息會建議使用者連線鍵盤 (系統未偵測到鍵盤時):
if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) { SuggestKeyboardConnect() }
確認裝置是否支援攝影機和麥克風
部分裝置不支援攝影機或麥克風。
您可以使用 hasCamera 參數和 hasMicrophone 參數,檢查裝置是否支援攝影機和麥克風。如果裝置支援攝影機和麥克風,系統會顯示下列按鈕:
Row { OutlinedTextField(state = rememberTextFieldState()) // Show the MicButton when the device supports a microphone. if (mediaQuery { hasMicrophone }) { MicButton() } // Show the CameraButton when the device supports a camera. if (mediaQuery { hasCamera }) { CameraButton() } }
根據預估觀看距離調整 UI
觀看距離是決定版面配置的因素之一。
如果使用者從遠處使用應用程式,會希望文字和 UI 元素放大。viewingDistance 參數會根據裝置類型和一般使用情境,估算觀看距離。
UiMediaScope.ViewingDistance 類別中定義了三個值:Near、Medium 和 Far。Near 表示螢幕在近距離範圍內,Far 則表示裝置是從遠處觀看。以下範例會在觀看距離為 Far 或 Medium 時,增加字型大小:
val fontSize = when { mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp else -> 16.sp }
預覽 UI 元件
您可以在可組合函式中呼叫 mediaQuery 和 derivedMediaQuery 函式,預覽 UI 元件。下列程式碼片段會根據 windowPosture 參數值,選擇 TabletopLayout 和 FlatLayout。
如要預覽 TabletopLayout,windowPosture 參數應為 UiMediaScope.Posture.Tabletop。
when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() }
mediaQuery 和 derivedMediaQuery 函式會在 UiMediaScope 物件中評估指定的 query lambda,該物件會以 LocalUiMediaScope.current 形式提供。如要覆寫這項設定,請按照下列步驟操作:
- 啟用
mediaQuery函式。 - 定義實作
UiMediaScope介面的自訂物件。 - 使用
CompositionLocalProvider函式,將自訂物件設為LocalUiMediaScope。 - 在
CompositionLocalProvider函式的內容 lambda 中呼叫可組合函式,即可預覽。
您可以透過下列範例預覽 TabletopLayout:
@Preview @Composable fun PreviewLayoutForTabletop() { // Step 1: Enable the mediaQuery function ComposeUiFlags.isMediaQueryIntegrationEnabled = true val currentUiMediaScope = LocalUiMediaScope.current // Step 2: Define a custom object implementing the UiMediaScope interface. // The object overrides the windowPosture parameter. // The resolution of the remaining parameters is deferred to the currentUiMediaScope object. val uiMediaScope = remember(currentUiMediaScope) { object : UiMediaScope by currentUiMediaScope { override val windowPosture: UiMediaScope.Posture = UiMediaScope.Posture.Tabletop } } // Step 3: Set the object to the LocalUiMediaScope. CompositionLocalProvider(LocalUiMediaScope provides uiMediaScope) { // Step 4: Call the composable to preview. when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() } } }