수정자를 사용하면 컴포저블을 장식하거나 강화할 수 있습니다. 수정자를 통해 다음과 같은 종류의 작업을 실행할 수 있습니다.
- 컴포저블의 크기, 레이아웃, 동작 및 모양 변경
- 접근성 라벨과 같은 정보 추가
- 사용자 입력 처리
- 요소를 클릭 가능, 스크롤 가능, 드래그 가능 또는 확대/축소 가능하게 만드는 높은 수준의 상호작용 추가
수정자는 표준 Kotlin 객체입니다. Modifier
클래스 함수 중 하나를 호출하여 수정자를 만듭니다.
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
다음과 같이 이러한 함수를 함께 연결하여 구성할 수 있습니다.
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
위의 코드에서 다양한 수정자 함수가 함께 사용된 것을 확인할 수 있습니다.
padding
: 요소 주위에 공간을 배치합니다.fillMaxWidth
: 컴포저블이 상위 요소로부터 부여받은 최대 너비를 채우도록 합니다.
모든 컴포저블이 modifier
매개변수를 허용하고 UI를 내보내는 첫 번째 하위 요소에 이 수정자를 전달하도록 하는 것이 좋습니다.
이렇게 하면 코드의 재사용 가능성이 커지며 코드 동작이 더 예측 가능해지고 이해하기 쉬워집니다. 자세한 내용은 Compose API 가이드라인, 수정자 매개변수를 허용 및 준수하는 요소를 참고하세요.
수정자의 순서가 중요
수정자 함수의 순서는 중요합니다. 각 함수는 이전 함수에서 반환한 Modifier
를 변경하므로 순서는 최종 결과에 영향을 줍니다. 다음 예를 살펴보겠습니다.
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
위의 코드에서는 padding
수정자가 clickable
수정자 뒤에 적용되었기 때문에 주변 패딩을 포함하여 전체 영역을 클릭할 수 있습니다. 수정자 순서가 뒤집히면 다음과 같이 padding
으로 추가된 공간은 사용자 입력에 반응하지 않습니다.
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
내장 수정자
Jetpack Compose는 컴포저블을 장식하거나 강화하는 데 도움이 되는 내장 수정자 목록을 제공합니다. 다음은 레이아웃을 조정하는 데 사용하는 몇 가지 일반적인 수정자입니다.
padding
및 size
기본적으로 Compose에서 제공되는 레이아웃은 하위 요소를 래핑합니다. 그러나 size
수정자를 사용하여 크기를 설정할 수 있습니다.
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
지정한 크기가 레이아웃의 상위 요소에서 수신된 제약 조건을 충족하지 않는 경우 적용되지 않을 수 있습니다. 수신된 제약 조건과 관계없이 컴포저블의 크기를 고정해야 하는 경우 requiredSize
수정자를 사용하세요.
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
이 예에서는 상위 요소 height
가 100.dp
로 설정되더라도 Image
높이는 150.dp
가 됩니다. requiredSize
수정자가 우선하기 때문입니다.
하위 레이아웃이 상위 요소에 의해 허용된 모든 가용 높이를 채우도록 하려면 fillMaxHeight
수정자를 추가합니다(Compose는 fillMaxSize
및 fillMaxWidth
도 제공함).
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
요소 주위에 패딩을 추가하려면 padding
수정자를 설정합니다.
레이아웃 상단에서 기준선까지 특정 거리가 유지되도록 텍스트 기준선 위에 패딩을 추가하려면 paddingFromBaseline
수정자를 사용합니다.
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
오프셋
원래 위치를 기준으로 레이아웃을 배치하려면 offset
수정자를 추가하고 x축과 y축에 오프셋을 설정합니다.
오프셋은 양수일 수도 있고 양수가 아닐 수도 있습니다. padding
과 offset
의 차이점은 컴포저블에 offset
를 추가해도 측정값이 변경되지 않는다는 것입니다.
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
offset
수정자는 레이아웃 방향에 따라 가로로 적용됩니다.
왼쪽에서 오른쪽으로 컨텍스트에서 양수 offset
은 요소를 오른쪽으로 이동하고 오른쪽에서 왼쪽으로 컨텍스트에서는 요소를 오른쪽으로 이동합니다.
레이아웃 방향을 고려하지 않고 오프셋을 설정해야 하는 경우 양의 오프셋 값이 항상 요소를 오른쪽으로 이동시키는 absoluteOffset
수정자를 확인하세요.
offset
수정자는 오버로드 두 개를 제공합니다. 오프셋을 매개변수로 사용하는 offset
과 람다를 사용하는 offset
입니다.
각각을 사용하는 시기와 성능을 위해 이를 최적화하는 방법에 관한 자세한 내용은 Compose 성능 - 최대한 읽기 연기 섹션을 참고하세요.
Compose의 범위 안전성
Compose에는 특정 컴포저블의 하위 요소에 적용될 때만 사용할 수 있는 수정자가 있습니다. Compose는 맞춤 범위를 통해 이를 적용합니다.
예를 들어 하위 요소를 Box
크기에 영향을 미치지 않고 상위 Box
만큼 크게 만들려면 matchParentSize
수정자를 사용합니다. matchParentSize
는 BoxScope
에서만 사용할 수 있습니다.
따라서 Box
상위 요소 내 하위 요소에만 사용할 수 있습니다.
범위 안전성을 사용하면 다른 컴포저블 및 범위에서 작동하지 않는 수정자를 추가할 수 없으며 시행착오로부터 시간을 절약할 수 있습니다.
범위 지정 수정자는 상위 요소가 하위 요소에 관해 알아야 하는 정보를 상위 요소에 알립니다. 일반적으로 상위 데이터 수정자라고도 합니다. 내��� ���소��� ���용 수정자와 다르지만 사용 관점에서 이러한 차이는 중요하지 않습니다.
Box
효과의 matchParentSize
위에서 언급했듯이 하위 레이아웃이 Box
크기에 영향을 미치지 않고 상위 Box
와 크기가 같이지도록 하려면 matchParentSize
수정자를 사용하세요.
matchParentSize
는 Box
범위 내에서만 사용할 수 있습니다. 즉 Box
컴포저블의 직접 하위 요소에만 적용됩니다.
아래 예에서 하위 Spacer
는 상위 Box
에서 크기를 가져오고 결과적으로 가장 큰 하위 요소(이 경우에는 ArtistCard
)에서 크기를 가져옵니다.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
matchParentSize
대신 fillMaxSize
가 사용된 경우 Spacer
는 허용된 모든 가용 공간을 상위 요소로 가져온 다음 상위 요소에서 모든 가용 공간을 확장하고 채웁니다.
Row
및 Column
의 weight
이전 패딩 및 크기 섹션에서 확인했듯이 기본적으로 컴포저블 크기는 컴포저블이 래핑하는 콘텐츠로 정의됩니다. RowScope
및 ColumnScope
에서만 사용할 수 있는 weight
수정자를 사용하여 컴포저블 크기를 상위 요소 내에서 유연하게 설정할 수 있습니다.
두 Box
컴포저블이 포함된 Row
를 사용해 보겠습니다.
첫 번째 상자의 weight
가 두 번째 상자의 두 배로 지정되므로 너비가 두 배로 지정됩니다. Row
의 너비가 210.dp
이므로 첫 번째 Box
의 너비는 140.dp
이고 두 번째는70.dp
입니다.
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
수정자 추출 및 재사용
여러 수정자를 함께 체이닝하여 컴포저블을 장식하거나 강화할 수 있습니다. 이 체인은 단일 Modifier.Elements
의 순서가 지정된 변경 불가능한 목록을 나타내는 Modifier
인터페이스를 통해 생성됩니다.
각 Modifier.Element
는 레이아웃, 그리기 및 그래픽 동작, 모든 동작 관련, 포커스 및 시맨틱 동작 ���의 개별 동작과 기기 입력 이벤트를 나타냅니다. 순서가 중요합니다. 먼저 추가된 수정자 요소가 먼저 적용됩니다.
변수로 추출하고 더 높은 범위로 끌어올리는 방식으로 동일한 수정자 체인 인스턴스를 여러 컴포저블에서 재사용하는 것이 유용할 수도 있습니다. 이는 다음과 같은 이유로 코드 가독성을 개선하거나 앱의 성능 개선에 도움이 될 수 있습니다.
- 수정자를 사용하는 컴포저블에 리컴포지션이 발생할 때 수정자의 재할당이 반복되지 않습니다.
- 수정자 체인은 매우 길고 복잡할 수 있으므로 동일한 체인 인스턴스를 재사용하면 Compose 런타임이 이를 비교할 때 해야 하는 워크로드를 줄일 수 있습니다.
- 이러한 추출을 통해 코드베이스 전체에서 코드 청결도, 일관성, 유지관리성이 향상됩니다.
수정자 재사용 권장사항
자체 Modifier
체인을 만들고 추출하여 여러 컴포저블 구성요소에서 재사용합니다. 수정자는 데이터와 같은 객체이므로 저장해도 괜찮습니다.
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
자주 변경되는 상태를 관찰할 때 수정자 추출 및 재사용
애니메이션 상태나 scrollState
처럼 컴포저블 내에서 자주 변경되는 상태를 관찰할 때 리컴포지션이 상당히 많이 발생할 수 있습니다. 이 경우 모든 리컴포지션 및 잠재적으로 모든 프레임에 수정자가 할당됩니다.
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
대신 다음과 같이 수정자의 동일한 인스턴스를 생성, 추출, 재사용한 후 컴포저블에 전달할 수 있습니다.
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
범위가 지정되지 않은 수정자 추출 및 재사용
수정자는 범위가 지정되지 않거나 특정 컴포저블로 범위가 지정될 수 있습니다. 범위가 지정되지 않은 수정자의 경우 컴포저블 외부에서 수정자를 간단한 변수로 쉽게 추출할 수 있습니다.
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
이는 Lazy 레이아웃과 함께 사용하면 특히 유용합니다. 대부분의 경우 잠재적으로 중요한 항목에 모두 정확히 동일한 수정자를 사용하는 것이 좋습니다.
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
범위 지정 수정자 추출 및 재사용
특정 컴포저블로 범위가 지정된 수정자를 처리할 때 가능한 한 가장 높은 수준으로 수정자를 추출하고 적절한 경우 재사용할 수 있습니다.
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
추출된 범위 지정 수정자는 동일한 범위의 직접 하위 요소에만 전달해야 합니다. 이것이 중요한 이유를 자세히 알아보려면 Compose의 범위 안전성 섹션을 참고하세요.
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
추출된 수정자의 추가 체이닝
추출된 수정자 체인은 .then()
함수를 호출하여 더 체이닝하거나 추가할 수 있습니다.
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
수정자 순서가 중요하다는 점을 유의해야 합니다.
자세히 알아보기
Google에서는 매개변수 및 범위가 포함된 수정자 전체 목록을 제공합니다.
수정자를 사용하는 방법에 관한 자세한 내용은 Compose의 기본 레이아웃 Codelab을 살펴보거나 Now in Android 저장���를 참고하세요.
맞춤 수정자와 이를 만드는 방법에 관한 자세한 내용은 맞춤 레이아웃 - 레이아웃 수정자 사용에 관한 문서를 참고하세요.
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- Compose 레이아웃 기본사항
- 편집자 작업 {:#editor-actions}
- 맞춤 레이아웃{:#custom-layouts }