Material 3 Expressive는 차세대 Material Design입니다. 업데이트된 테마 설정, 구성요소, 맞춤설정 기능(동적 색상 등)을 포함합니다.
이 가이드에서는 앱의 Wear Compose Material 2.5(androidx.wear.compose) Jetpack 라이브러리에서 Wear Compose Material 3(androidx.wear.compose.material3) Jetpack 라이브러리로의 이전을 중점적으로 설명합니다.
접근 방식
앱 코드를 M2.5에서 M3로 이전하려면 Compose Material 이전 휴대전화 가이드에 설명된 것과 동일한 접근 방식을 따르세요. 특히 다음을 참고하세요.
- 하나의 앱에서 M2.5와 M3 둘 다를 장기적으로 사용해서는 안 됩니다.
- 더 이상 Horologist Composables, Compose Layout 또는 Compose Material 라이브러리를 사용하지 않아야 합니다. 대신 M3의 구성요소를 사용하세요.
- 단계별 접근 방식을 채택합니다.
종속 항목
M3에는 M2.5와 별개인 패키지 및 버전이 있습니다.
M2.5
implementation("androidx.wear.compose:compose-material:1.4.0")
M3
implementation("androidx.wear.compose:compose-material3:1.8.0-alpha02")
Wear Compose 출시 페이지에서 최신 M3 버전을 참고하세요.
Wear Compose Foundation 라이브러리 버전 1.8.0-alpha02에는 Material 3 구성요소와 함께 작동하도록 설계된 몇 가지 새로운 구성요소가 도입되었습니다.
마찬가지로 Wear Compose Navigation 라이브러리의 SwipeDismissableNavHost는 Wear OS 6 (API 수준 36) 이상에서 실행될 때 애니메이션이 업데이트됩니다. Wear Compose Material 3 버전으로 업데이트할 때는 Wear Compose Foundation 및 Navigation 라이브러리도 업데이트하는 것이 좋습니다.
implementation("androidx.wear.compose:compose-foundation:1.8.0-alpha02")
implementation("androidx.wear.compose:compose-navigation:1.8.0-alpha02")
테마
M2.5와 M3에서 테마 컴포저블의 이름은 MaterialTheme이지만 가져오기 패키지와 매개변수는 다음과 같이 다릅니다. M3에서는 Colors 매개변수의 이름이 ColorScheme로 변경되었으며 전환을 구현하기 위해 MotionScheme가 도입되었습니다.
M2.5
import androidx.wear.compose.material.MaterialTheme
MaterialTheme(
colors = AppColors,
typography = AppTypography,
shapes = AppShapes,
content = content
)
M3
import androidx.wear.compose.material3.MaterialTheme // ... MaterialTheme( colorScheme = ColorScheme(), typography = Typography(), shapes = Shapes(), motionScheme = MotionScheme.standard(), content = { /*content here*/ } )
색상
M3의 색상 시스템은 M2.5와 매우 다릅니다. 색상 매개변수의 수가 많아졌고 이름도 다르며 M3 구성요소에 다른 방식으로 매핑됩니다. Compose에서 이는 M2.5 Colors 클래스, M3 ColorScheme 클래스 및 관련 함수에 적용됩니다.
M2.5
import androidx.wear.compose.material.Colors
val appColorScheme: Colors = Colors(
// M2.5 Color parameters
)
M3
import androidx.wear.compose.material3.ColorScheme // ... val appColorScheme: ColorScheme = ColorScheme( // M3 ColorScheme parameters )
다음 표에서는 M2.5와 M3의 주요 차이점을 설명합니다.
| M2.5 | M3 |
|---|---|
Colors |
ColorScheme(으)로 이름이 변경되었습니다. |
| 13가지 색상 | 29가지 색상 |
| 해당 사항 없음 | 새로운 동적 색상 테마 설정 |
| 해당 사항 없음 | 더 풍부한 표현을 위한 새로운 3차 색상 |
동적 색상 테마 설정
M3의 새로운 기능은 동적 색상 테마 설정입니다. 사용자가 워치 페이스 색상을 변경하면 UI의 색상이 이에 맞게 변경됩니다.
dynamicColorScheme 함수를 사용하여 동적 색 구성표를 구현하고 동적 색 구성표를 사용할 수 없는 경우 대체로 defaultColorScheme를 제공합니다.
@Composable fun myApp() { val dynamicColorScheme = dynamicColorScheme(LocalContext.current) MaterialTheme(colorScheme = dynamicColorScheme ?: myBrandColors) {} } internal val myBrandColors: ColorScheme = ColorScheme( /* Specify colors here */)
서체
M3의 서체 시스템은 M2.5와 다르며 다음 기능을 포함합니다.
- 새로운 텍스트 스타일 9개
- 다양한 두께, 너비, 둥글기에 맞게 유형 배율을 맞춤설정할 수 있는 가변 글꼴
AnimatedText: 가변 글꼴을 사용합니다.
M2.5
import androidx.wear.compose.material.Typography
val Typography = Typography(
// M2.5 TextStyle parameters
)
M3
import androidx.wear.compose.material3.Typography val Typography = Typography( // M3 TextStyle parameters )
Flex 글꼴
Flex 글꼴을 사용하면 디자이너가 특정 크기의 글꼴 너비와 두께를 지정할 수 있습니다.
텍스트 스타일
M3에서는 다음과 같은 TextStyles를 사용할 수 있습니다. 이러한 색상은 다양한 M3 구성요소에서 기본적으로 사용됩니다.
| 서체 | TextStyle |
|---|---|
| 디스플레이 | displayLarge, displayMedium, displaySmall |
| 제목 | titleLarge, titleMedium, titleSmall |
| 라벨 | labelLarge, labelMedium, labelSmall |
| 본문 | bodyLarge, bodyMedium, bodySmall, bodyExtraSmall |
| 수사 | numeralExtraLarge, numeralLarge, numeralMedium, numeralSmall, numeralExtraSmall |
| Arc | arcLarge, arcMedium, arcSmall |
도형
M3의 도형 시스템은 M2.5와 다릅니다. 도형 매개변수의 수가 많아졌고 이름이 다르게 지정되었으며 M3 구성요소에 다르게 매핑됩니다. 사용 가능한 도형 크기는 다음과 같습니다.
- 매우 작게
- 작게
- 보통
- 크게
- 매우 크게
Compose에서 이는 M2.5 Shapes 클래스와 M3 Shapes 클래스에 적용됩니다.
M2.5
import androidx.wear.compose.material.Shapes
val Shapes = Shapes(
// M2.5 Shapes parameters
)
M3
import androidx.wear.compose.material3.Shapes val Shapes = Shapes( // M3 Shapes parameters )
Compose의 Material 2에서 Material 3으로 이전의 도형 매개변수 매핑을 시작점으로 사용합니다.
도형 변형
M3에는 도형 변형이 도입되었습니다. 이제 도형이 상호작용에 따라 변형됩니다.
도형 변형 동작은 여러 원형 버튼의 변형으로 사용할 수 있습니다. 도형 변형을 지원하는 버튼 목록은 다음과 같습니다.
| 버튼 | 도형 변형 함수 |
|---|---|
IconButton |
IconButtonDefaults.animatedShapes는 누를 때 아이콘 버튼에 애니메이션을 적용합니다. |
IconToggleButton |
IconToggleButtonDefaults.animatedShapes는 누를 때 아이콘 전환 버튼에 애니메이션을 적용하고 IconToggleButtonDefaults.variantAnimatedShapes는 누를 때와 선택/선택 해제할 때 아이콘 전환 버튼에 애니메이션을 적용합니다. |
TextButton |
TextButtonDefaults.animatedShapes는 누를 때 텍스트 버튼에 애니메이션을 적용합니다. |
TextToggleButton |
TextToggleButtonDefaults.animatedShapes는 누를 때 텍스트 전환에 애니메이션을 적용하고 TextToggleButtonDefaults.variantAnimatedShapes는 누를 때와 선택/선택 해제할 때 텍스트 전환에 애니메이션을 적용합니다. |
구성요소 및 레이아웃
M2.5의 구성요소와 레이아웃은 대부분 M3에서 사용할 수 있습니다. 그러나 일부 M3 구성요소와 레이아웃은 M2.5에 없었습니다. 또한 일부 M3 구성요소에는 상응하는 M2.5 요소보다 더 많은 변형이 있습니다.
일부 구성요소에는 특별한 고려사항이 필요하지만, 다음과 같은 함수 매핑을 시작점으로 사용하는 것이 좋습니다.
다음은 일반적인 Material 3 구성요소와 이에 상응하는 Material 2.5 구성요소의 목록입니다.
마지막으로 Wear Compose Foundation 라이브러리의 관련 구성요소 목록입니다.
| Wear Compose Foundation 1.8.0-alpha02 | |
|---|---|
| androidx.wear.compose.foundation.hierarchicalFocusGroup | 애플리케이션에서 컴포저블에 주석을 달아 컴포지션의 활성 부분을 추적하고 포커스를 조정하는 데 사용됩니다. |
| androidx.wear.compose.foundation.pager.HorizontalPager | Compose Foundation 구성요소를 기반으로 빌드된 가로 스크롤 페이저로, Wear OS 가이드라인 준수 및 성능 개선을 위한 Wear 관련 개선사항이 포함되어 있습니다. |
| androidx.wear.compose.foundation.pager.VerticalPager | Wear OS 가이드라인 준수 및 성능 개선을 위해 Wear OS 전용 개선사항이 적용된 Compose Foundation 구성요소를 기반으로 빌드된 세로 스크롤 페이저입니다. |
| androidx.wear.compose.foundation.lazy.TransformingLazyColumn | ScalingLazyColumn 대신 사용하여 각 항목에 스크롤 변환 효과를 추가할 수 있습니다. |
버튼
M3의 버튼은 M2.5와 다릅니다. M2.5 칩이 버튼으로 대체되었습니다. Button 구현은 Text, maxLines, textAlign의 기본값을 제공합니다. 이러한 기본값은 Text 요소에서 재정의할 수 있습니다.
M2.5
import androidx.wear.compose.material.Chip
//M2.5 Buttons
Chip(...)
CompactChip(...)
Button(...)
M3
//M3 Buttons Button(onClick = { }){} CompactButton(onClick = { }){} IconButton(onClick = { }){} TextButton(onClick = { }){}
M3에는 새로운 버튼 변형도 있습니다. Compose Material 3 API 참조 개요에서 확인하세요.
M3에는 새로운 버튼인 EdgeButton가 도입되었습니다. EdgeButton은 초소형, 소형, 중형, 대형의 4가지 크기로 제공됩니다. EdgeButton 구현은 맞춤설정할 수 있는 크기에 따라 maxLines의 기본값을 제공합니다.
TransformingLazyColumn 또는 ScalingLazyColumn를 사용하는 경우 EdgeButton를 최종 목록 항목으로 추가하는 대신 EdgeButton를 ScreenScaffold에 전달하여 스크롤에 따라 모양이 변경되도록 합니다. ScreenScaffold 및 TransformingLazyColumn와 함께 EdgeButton를 사용하는 방법을 확인하려면 다음 코드를 참고하세요.
val state = rememberTransformingLazyColumnState() ScreenScaffold( scrollState = state, edgeButton = { EdgeButton( onClick = { }, modifier = Modifier.scrollable( state, orientation = Orientation.Vertical, reverseDirection = true, // Apply overscroll to the EdgeButton for proper scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), ) { Text(stringResource(R.string.show)) } }, ) { contentPadding -> TransformingLazyColumn(state = state, contentPadding = contentPadding) { // additional code here // ... } }
Scaffold
M3의 스캐폴드는 M2.5와 다릅니다. M3에서는 AppScaffold 및 새 ScreenScaffold 컴포저블이 스캐폴드를 대체했습니다. AppScaffold 및 ScreenScaffold는 화면의 구조를 배치하고 ScrollIndicator 및 TimeText 구성요소의 전환을 조정합니다.
AppScaffold를 사용하면 스와이프하여 닫기와 같은 인앱 전환 중에 TimeText와 같은 정적 화면 요소가 계속 표시됩니다. 기본 애플리케이션 콘텐츠를 위한 슬롯을 제공하며, 이 콘텐츠는 일반적으로 SwipeDismissableNavHost과 같은 탐색 구성요소에서 제공됩니다.
활동에 대해 하나의 AppScaffold를 선언하고 각 화면에 ScreenScaffold를 사용합니다.
AppScaffold는 기본 TimeText 구성요소를 화면에 추가합니다. timeText 매개변수를 사용하여 맞춤설정하려는 경우 재정의할 수 있습니다.
M2.5
import androidx.wear.compose.material.Scaffold
Scaffold {...}
M3
AppScaffold { val navController = rememberSwipeDismissableNavController() SwipeDismissableNavHost( navController = navController, startDestination = "message_list" ) { composable("message_list") { MessageList(onMessageClick = { id -> navController.navigate("message_detail/$id") }) } composable("message_detail/{id}") { MessageDetail(id = it.arguments?.getString("id")!!) } } } } // Implementation of one of the screens in the navigation @Composable fun MessageDetail(id: String) { // .. Screen level content goes here val scrollState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = scrollState, ) { contentPadding -> // Screen content goes here // ...
HorizontalPageIndicator와 함께 HorizontalPager를 사용하는 경우 HorizontalPagerScaffold로 마이그레이션할 수 있습니다. HorizontalPagerScaffold는 AppScaffold 내에 배치됩니다. AppScaffold 및 HorizontalPagerScaffold는 페이저의 구조를 배치하고 HorizontalPageIndicator 및 TimeText 구성요소의 전환을 조정합니다.
HorizontalPagerScaffold는 기본적으로 화면 중앙 끝에 HorizontalPageIndicator를 표시하고 Pager가 페이징되는지 여부에 따라 TimeText 및 HorizontalPageIndicator 표시 및 숨기기를 조정합니다. 이는 PagerState에 의해 결정됩니다.
또한 위치에 따라 크기 조절 및 스크림 효과를 사용하여 페이저 내의 페이지에 애니메이션을 적용하는 새로운 AnimatedPage 구성요소도 있습니다.
AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPagerScaffold(pagerState = pagerState) { HorizontalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState, ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding, ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( ListHeaderDefaults.minimumTopListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { Text(text = "Pager sample") } } item { Card( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( CardDefaults.minimumVerticalListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { if (page == 0) { Text(text = "Page #$page. Swipe right") } else { Text(text = "Page #$page. Swipe left and right") } } } } } } } } }
마지막으로, M3는 HorizontalPagerScaffold와 동일한 패턴을 따르는 VerticalPagerScaffold를 도입합니다.
@Composable fun VerticalPagerScaffoldSample() { AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPagerScaffold(pagerState = pagerState) { VerticalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe up and down") } } } } } } }
플레이스홀더
M2.5와 M3 간에 몇 가지 API 변경사항이 있습니다. M3는 두 가지 자리표시자 수정자를 제공합니다.
Modifier.placeholder: 아직 로드되지 않은 콘텐츠 대신 그려집니다.- 데이터가 로드되기를 기다리는 동안 애니메이션 루프에서 실행되는 플레이스홀더 쉬머 효과를 제공하는 플레이스홀더 쉬머 효과
Modifier.placeholderShimmer입니다.
Placeholder 구성요소의 추가 변경사항은 다음 표를 참고하세요.
| M2.5 | M3 |
|---|---|
PlaceholderState.startPlaceholderAnimation |
삭제됨 |
PlaceholderState.placeholderProgression |
삭제됨 |
PlaceholderState.isShowContent |
PlaceholderState.isVisible (반전된 불리언)로 대체됨 |
PlaceholderState.isWipeOff |
삭제됨 |
PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush |
삭제됨 |
PlaceholderDefaults.placeholderBackgroundBrush |
삭제됨 |
PlaceholderDefaults.placeholderChipColors |
삭제됨 |
SwipeDismissableNavHost
SwipeDismissableNavHost은(는) wear.compose.navigation의 일부입니다. 이 구성요소를 M3과 함께 사용하면 M3 MaterialTheme이 LocalSwipeToDismissBackgroundScrimColor 및 LocalSwipeToDismissContentScrimColor를 업데이트합니다.
TransformingLazyColumn
TransformingLazyColumn은 androidx.wear.compose.foundation.lazy의 일부이며 스크롤 중에 목록 항목의 크기 조절 및 모핑 애니메이션 지원을 추가하여 사용자 환경을 개선합니다. 앱을 ScalingLazyColumn에서 TransformingLazyColumn로 이전하는 것이 좋습니다.
ScalingLazyColumn와 마찬가지로, 컴포지션 간에 기억되는 TransformingLazyColumnState를 만드는 rememberTransformingLazyColumnState()를 제공합니다.
확장 및 변형 애니메이션을 추가하려면 각 목록 항목에 다음을 추가합니다.
Modifier.transformedHeight:TransformationSpec를 사용하여 항목의 변환된 높이를 계산할 수 있습니다. 추가 맞춤설정이 필요하지 않은 경우rememberTransformationSpec()를 사용할 수 있습니다.SurfaceTransformation
목록의 상단과 하단에 패딩이 올바른지 확인하려면 minimumVerticalContentPadding 수정자를 사용합니다.
val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding), transformation = SurfaceTransformation(transformationSpec) ) { Text(text = "Header") } } // ... other items item { Button( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding), transformation = SurfaceTransformation(transformationSpec), onClick = { /* ... */ }, icon = { Icon( imageVector = Icons.Default.Build, contentDescription = "build", ) }, ) { Text( text = "Build", maxLines = 1, overflow = TextOverflow.Ellipsis, ) } } } }
유용한 링크
Compose에서 M2.5에서 M3으로 이전하는 방법에 관한 자세한 내용은 다음 추가 리소스를 참고하세요.