Compose 규칙 중 하나는 하위 요소를 한 번만 측정해야 한다는 것입니다. 하위 요소를 두 번 측정하면 런타임 예외가 발생합니다. 하지만 하위 요소를 측정하기 전에 하위 요소에 관한 정보가 필요한 경우도 있습니다.
내장 기능을 사용하면 하위 요소가 실제로 측정되기 전에 하위 요소를 쿼리할 수 있습니다.
컴포저블에 intrinsicWidth
또는 intrinsicHeight
를 요청할 수 있습니다.
(min|max)IntrinsicWidth
: 이 너비에서 콘텐츠를 적절하게 그릴 수 있는 최소/최대 너비는 무엇인가요?(min|max)IntrinsicHeight
: 이 높이에서 콘텐츠를 적절하게 그릴 수 있는 최소/최대 높이는 무엇인가요?
예를 들어 height
가 무한대인 Text
의 minIntrinsicHeight
를 요청하면 텍스트가 한 줄에 그려진 것처럼 Text
의 height
가 반환됩니다.
내장 기능 실제 사례
다음과 같이 화면에 구분선으로 구분된 두 텍스트를 표시하는 컴포저블을 만든다고 가정해 보겠습니다.
이렇게 하려면 어떻게 해야 하나요? 안에 두 Text
가 있고 최대한 확장할 수 있으며 중앙에 Divider
가 있는 Row
를 만들 수 있습니다. Divider
를 가장 높은 Text
만큼 높고 가늘게 (width = 1.dp
) 만들려고 합니다.
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) HorizontalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
미리 보면 Divider
가 전체 화면으로 확장되며 이는 원하는 결과가 아닙니다.
Row
가 각 하위 요소를 개별적으로 측정하며 Text
의 높이를 사용하여 Divider
를 제약할 수 없기 때문에 이러한 결과가 발생합니다. Divider
가 가용 공간을 지정된 높이로 채우도록 하려고 합니다. 이를 위해 height(IntrinsicSize.Min)
수정자를 사용할 수 있습니다.
height(IntrinsicSize.Min)
는 하위 요소의 크기를 고유한 최소 높이로 강제 지정합니다. 이 기능은 반복적이므로 Row
및 하위 minIntrinsicHeight
를 쿼리합니다.
코드에 적용하면 예상대로 작동합니다.
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier.height(IntrinsicSize.Min)) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) HorizontalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } } // @Preview @Composable fun TwoTextsPreview() { MaterialTheme { Surface { TwoTexts(text1 = "Hi", text2 = "there") } } }
미리보기는 다음과 같습니다.
Row
컴포저블의 minIntrinsicHeight
가 하위 요소의 최대 minIntrinsicHeight
입니다. Divider
요소의 minIntrinsicHeight
는 제약 조건이 주어지지 않으면 공간을 차지하지 않으므로 0입니다. Text
minIntrinsicHeight
는 특정 width
가 지정된 경우 텍스트의 높이입니다. 따라서 Row
요소의 height
제약 조건은 Text
의 최대 minIntrinsicHeight
입니다. 그런 다음 Divider
가 height
를 Row
가 지정한 height
제약 조건으로 확장합니다.
맞춤 레이아웃의 내장 기능
맞춤 Layout
또는 layout
수정자를 만들 때 내장 기능 측정은 근사값에 따라 자동으로 계산됩니다. 따라서 일부 레이아웃의 계산은 정확하지 않을 수 있습니다. 이러한 API는 이와 같은 기본값을 재정의하는 옵션을 제공합니다.
맞춤 Layout
의 내장 기능 측정을 지정하려면 만들 때 MeasurePolicy
인터페이스의 minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
, maxIntrinsicHeight
를 재정의하세요.
@Composable fun MyCustomComposable( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( content = content, modifier = modifier, measurePolicy = object : MeasurePolicy { override fun MeasureScope.measure( measurables: List<Measurable>, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurables: List<IntrinsicMeasurable>, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
맞춤 layout
수정자를 만들 때 LayoutModifier
인터페이스에서 관련 메서드를 재정의합니다.
fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- 맞춤 레이아웃 {:#custom-layouts }
- Jetpack Compose의 정렬 선
- Jetpack Compose 단계