시배's Android

Compose Docs | Instrinsic measurements 본문

Android/Compose Docs

Compose Docs | Instrinsic measurements

si8ae 2023. 9. 5. 00:02
 

Compose 레이아웃의 내장 기능 측정  |  Jetpack Compose  |  Android Developers

Compose 레이아웃의 내장 기능 측정 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Compose 규칙 중 하나는 하위 요소를 한 번만 측정해야 한다는 것입니다. 하

developer.android.com

Compose의 규칙 중 하나는 자녀를 한 번만 측정해야 하며, 자녀를 두 번 측정하면 런타임 예외가 발생한다는 것입니다. 그러나 자녀를 측정하기 전에 자녀에 대한 정보가 필요한 경우가 있습니다.

Intrinsics를 사용하면 실제로 측정하기 전에 자식에 대해 쿼리할 수 있습니다.
컴포저블에 대해, 그 컴포저블의 intrinsicWidth 또는 intrinsicHeight를 요청할 수 있습니다:
(최소|최대)IntrinsicWidth: 이 높이가 주어졌을 때 콘텐츠를 제대로 칠할 수 있는 최소/최대 너비는 얼마인가?
(최소|최대)IntrinsicHeight: 이 너비가 주어졌을 때 콘텐츠를 제대로 칠할 수 있는 최소/최대 높이는 얼마인가요?
예를 들어 너비가 무한대인 텍스트의 최소 내재 높이를 물어보면 텍스트가 한 줄로 그려진 것처럼 텍스트의 높이를 반환합니다.

Instrinsics in action

이렇게 디바이더로 구분된 두 개의 텍스트를 화면에 표시하는 컴포저블을 만들고 싶다고 가정해 보겠습니다:


어떻게 할 수 있을까요? 내부에 두 개의 텍스트가 있는 행을 최대한 확장하고 가운데에 디바이더를 배치하면 됩니다. 디바이더는 가장 긴 텍스트만큼 길고 얇아야 합니다(너비 = 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
        )
        Divider(
            color = Color.Black,
            modifier = Modifier.fillMaxHeight().width(1.dp)
        )
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = 4.dp)
                .wrapContentWidth(Alignment.End),

            text = text2
        )
    }
}

미리 보기를 보면 디바이더가 전체 화면으로 확장되는 것을 볼 수 있는데, 이는 우리가 원하는 것이 아닙니다:

이는 행이 각 자식을 개별적으로 측정하고 텍스트의 높이를 사용하여 디바이더를 제약할 수 없기 때문에 발생합니다. 우리는 디바이더가 주어진 높이로 사용 가능한 공간을 채우기를 원합니다. 이를 위해 높이(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
        )
        Divider(
            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가 됩니다. 제약 조건이 주어지지 않으면 공간을 차지하지 않으므로 Divider 엘리먼트의 minIntrinsicHeight는 0이 되고, Text 엘리먼트의 minIntrinsicHeight는 특정 너비가 지정된 텍스트의 높이가 됩니다. 따라서 행 요소의 높이 제약 조건은 텍스트의 최대 minIntrinsicHeight가 됩니다. 그러면 디바이더는 행에 지정된 높이 제약 조건까지 높이를 확장합니다.

Intrinsics in your custom layouts

사용자 정의 레이아웃 또는 레이아웃 수정자를 만들 때 근사치를 기반으로 내재적 측정값이 자동으로 계산됩니다. 따라서 모든 레이아웃에서 계산이 정확하지 않을 수 있습니다. 이러한 API는 이러한 기본값을 재정의할 수 있는 옵션을 제공합니다.
사용자 지정 레이아웃의 내재적 측정값을 지정하려면 레이아웃을 만들 때 측정정책 인터페이스의 최소 내재적 너비, 최소 내재적 높이, 최대 내재적 너비 및 최대 내재적 높이를 재정의합니다.

@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.
        }
    )
}

사용자 정의 레이아웃 수정자를 만들 때 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.
}

'Android > Compose Docs' 카테고리의 다른 글

Compose Docs | Custom Design Systems  (0) 2023.09.16
Compose Docs | ConstraintLayout  (0) 2023.09.06
Compose Docs | Alignment lines  (0) 2023.09.03
Compose Docs | Build adaptive layouts  (0) 2023.08.28
Compose Docs | Custom layouts  (0) 2023.08.26