앱 레이아웃을 업데이트하려면 기기 기능, 앱 상태 등 다양한 유형의 정보가 필요합니다. 창 너비와 높이는 가장 일반적으로 사용되는 정보입니다. 또한 다음 정보를 참고할 수 있습니다.
- 창 자세
- 포인팅 기기 정밀도
- 키보드 유형
- 기기에서 카메라와 마이크를 지원하는지 여부
- 사용자와 기기 디스플레이 간의 거리
정보가 동적으로 업데이트되므로 업데이트가 발생하면 이를 모니터링하고 리컴포지션을 트리거해야 합니다.
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 내에서 평가되는 람다로 조건을 정의할 수 있습니다.
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() } // ... }
창 크기에 따라 결정
창 크기 클래스는 적응형 레이아웃을 디자인하고 개발 및 테스트할 수 있는 체계적인 표시 영역 중단점입니다.
현재 창 크기를 나타내는 두 매개변수를 창 크기 클래스에 정의된 임계값과 비교할 수 있습니다.
다음 예에서는 창 너비에 따라 창 수를 변경합니다.
WindowSizeClass 클래스에는 창 크기 클래스의 기준점 상수가 있습니다 (그림 1).
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의 네 가지 값이 정의되어 있습니다.
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 함수는 LocalUiMediaScope.current로 제공되는 UiMediaScope 객체 내에서 주어진 query 람다를 평가합니다.
다음 단계에 따라 재정의할 수 있습니다.
mediaQuery함수를 사용 설정합니다.UiMediaScope인터페이스를 구현하는 맞춤 객체를 정의합니다.CompositionLocalProvider함수를 사용하여 맞춤 객체를LocalUiMediaScope로 설정합니다.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() } } }