アプリのレイアウトを更新するには、デバイスの機能やアプリのステータスなど、さまざまな種類の情報が必要です。 最も一般的に使用される情報は、ウィンドウの幅と高さです。この他に、次の情報を参照できます。
- ウィンドウの姿勢
- ポインティング デバイスの精度
- キーボード タイプ
- デバイスがカメラとマイクをサポートしているかどうか
- ユーザーとデバイスのディスプレイの間の距離
情報は動的に更新されるため、情報をモニタリングし、更新が発生したときに再コンポーズをトリガーする必要があります。
The mediaQuery 関数は、情報検索の詳細を抽象化し、レイアウトの更新をトリガーする条件の定義に集中できるようにします。次の例では、折りたたみ式デバイスの姿勢がテーブルトップの場合に、レイアウトを
TabletopLayout に切り替えます。
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
mediaQuery 関数を有効にする
mediaQuery 関数を有効にするには、
isMediaQueryIntegrationEnabled 属性を
ComposeUiFlags オブジェクトの true に設定します。
class MyApplication : Application() { override fun onCreate() { ComposeUiFlags.isMediaQueryIntegrationEnabled = true super.onCreate() } }
パラメータを使用して条件を定義する
条件は、ラムダ
として定義できます。これは、UiMediaScope内で評価されます。
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 ラムダを評価し、ブール値を返します。たとえば、次のスニペットでは、windowPosture パラメータの値に基づいて TabletopLayout と FlatLayout を選択します。
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
ウィンドウ サイズに基づいて決定する
ウィンドウ サイズクラスは、アダプティブ レイアウトの設計、開発、テストに役立つ独自のビューポート ブレークポイントのセットです。現在のウィンドウ サイズを表す 2 つのパラメータを、ウィンドウ サイズクラスで定義されたしきい値と比較できます。次の例では、ウィンドウの幅に応じてペインの数を変更します。
WindowSizeClass クラスには、ウィンドウ サイズクラスのしきい値の定数があります(図 1)。
The derivedMediaQuery 関数は query ラムダ
を評価し、結果を derivedStateOfでラップします。
windowWidth と windowHeight は頻繁に更新される可能性があるため、query
ラムダでこれらのパラメータを参照する場合は、mediaQuery 関数ではなく derivedMediaQuery 関数を呼び出します。
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 の 4 つの値が定義されています。
None は、ポインティング
デバイスが使用できないことを意味します。
精度は、Fine、Coarse、Blunt の順に高くなります。
複数のポインティング デバイスが使用可能で、精度が異なる場合、パラメータは最も高い精度で解決されます。
たとえば、Fine 精度のデバイスと
Blunt 精度のデバイスの 2 つのポインティング デバイスがある場合、pointerPrecision パラメータの値は Fine
になります。
次の例では、ユーザーが低精度のポインティング デバイスを使用している場合に、ボタンを大きく表示します。
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 の 3 つの値が定義されています。
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` 関数は、`LocalUiMediaScope.current` として提供される `UiMediaScope` オブジェクト内で、指定された `query` ラムダを評価します。次の手順でオーバーライドできます。
mediaQuery関数を有効にします。UiMediaScopeインターフェースを実装するカスタム オブジェクトを定義します。- カスタム オブジェクトを
LocalUiMediaScopeにCompositionLocalProvider関数を使用して設定します。 CompositionLocalProvider関数のコンテンツ ラムダでコンポーズ可能関数を呼び出してプレビューします。
次の例では、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() } } }