오늘은 WindowSize 란 것을 이용하여 기기마다 기기의 화면 크기에 따라 다른 UI를 제공하는 방법을 알아보겠습니다.
WindowSizeClass는 앱이 실행되는 창의 가용 공간을 너비와 높이 기준으로 세 가지 크기 범주로 분류합니다.
600dp600dp ≤ 너비 < 840dp840dp480dp480dp ≤ 높이 < 900dp900dpWindowSizeClass 를 사용하여 분류하면 앱이 다양한 화면 크기와 형태에 적용할 수 있는 반응형 UI를 구현할 수 있습니다.

이런 식으로 말이죠.
유저 입장에서는 훨씬 친화적이겠죠?
만약 테블릿에서도 스마트폰 UI를 사용하게 된다면 엄청 불편할 겁니다…
즉, WindowSizeClass 를 활용하여 사용자에게 일관되고 최적화된 경험을 제공할 수 있습니다.
그럼 바로 Compose에서 어떻게 사용할 수 있는지 보겠습니다.
androidx-windowSize = {group = "androidx.compose.material3", name = "material3-window-size-class"}
우선 의존성을 추가해줘야 WindowSizeClass 를 사용할 수 있습니다.
그리고 위 사진처럼 기기의 가로 화면에 따라 다른 UI를 제공해보겠습니다.
우선 기기의 사이즈정보를 가져올 수 있는 WindowSizeClass 를 가져오겠습니다.
val windowSize = calculateWindowSizeClass(this)
@ExperimentalMaterial3WindowSizeClassApi
@Composable
fun calculateWindowSizeClass(activity: Activity): WindowSizeClass {
LocalConfiguration.current
val density = LocalDensity.current
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(activity)
val size = with(density) { metrics.bounds.toComposeRect().size.toDpSize() }
return WindowSizeClass.calculateFromSize(size)
}
WindowSizeClass 에서 제공하는 calculateWindowSizeClass 를 사용하여 정보를 가져올 수 있습니다.
WindowSizeClass가 어떻게 작성되었을까요?
@Immutable
class WindowSizeClass private constructor(
val widthSizeClass: WindowWidthSizeClass,
val heightSizeClass: WindowHeightSizeClass
) {
value class WindowWidthSizeClass private constructor(private val value: Int) :
Comparable<WindowWidthSizeClass> {
companion object {
val Compact = WindowWidthSizeClass(0)
val Medium = WindowWidthSizeClass(1)
val Expanded = WindowWidthSizeClass(2)
}
value class WindowHeightSizeClass private constructor(private val value: Int) :
Comparable<WindowHeightSizeClass> {
companion object {
val Compact = WindowHeightSizeClass(0)
val Medium = WindowHeightSizeClass(1)
val Expanded = WindowHeightSizeClass(2)
}
}
WindowSizeClass 안에 value class로 Width와 Height 사이즈 클래스가 있고 그 안에 값에 따라 나뉘는 Compact , Medium , Expanded 로 나뉘고 있는 모습을 확인할 수 있습니다.
바로 이를 활용하여 기기 사이즈마다 다른 UI를 제공할 수 있습니다.
when (windowSize) {
WindowWidthSizeClass.Compact -> {
Scaffold(
bottomBar = { BottomNavigationBar(navController = navController) }
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding))
content(innerPadding)
}
}
WindowWidthSizeClass.Medium -> {
Scaffold { innerPadding ->
Row(modifier = Modifier.padding(innerPadding).fillMaxSize()) {
NavigationRailContent(navController = navController)
Box(modifier = Modifier.fillMaxSize().padding(start = 16.dp)) {
content(PaddingValues())
}
}
}
}
WindowWidthSizeClass.Expanded -> {
PermanentNavigationDrawer(
drawerContent = {
PermanentDrawerSheet(
modifier = Modifier.width(240.dp),
drawerContainerColor = MaterialTheme.colorScheme.inverseOnSurface
) { // PermanentDrawerSheet Scope
NavigationDrawerContent(navController = navController)
}
}
) {
Box(modifier = Modifier.fillMaxSize()) {
content(PaddingValues())
}
}
}
}
이런식으로 저는 WindowWidthSizeClass 의 값에 따라 다른 UI를 제공했습니다.
Compact 가장 기본적인 스마트폰 형태이기 때문에 바텀 네비게이션 바를 설정했습니다.Medium 일부 태블릿, 폴더블 휴대폰이기 때문에 NavigationRail 을 사용했습니다.Expanded 태블릿, 윈도우기 때문에 PermanentNavigationDrawer 를 사용했습니다.NavigationRail과 Drawer에 대한 자세한 내용은 링크에 들어가시면 자세한 내용을 확인하실 수 있습니다.
https://m3.material.io/components/navigation-rail/overview
https://developer.android.com/develop/ui/compose/layouts/adaptive/list-detail?hl=ko
https://developer.android.com/develop/ui/compose/layouts/adaptive/use-window-size-classes