IntrinsicSize 다루기

손현수·2024년 3월 15일

안드로이드 Compose

목록 보기
10/25

컴포즈에서는 종종 부모 컴포저블이 재구성 과정에서 자식을 측정하기 전부터 그 크기 정보를 알아야 하는 경우가 발생한다. 예를 들어, 폭이 가장 넓은 자식과 일치하도록 Column의 폭을 조절하기 위해 자식의 폭을 알아야 할 수 있다. 부모는 자식의 크기를 측정할 수 없지만, 내재적 측정값(intrinsic measurement)을 이용하면 크기 정보를 얻을 수 있다.

내재적 측정값

  • IntrinsicSize는 가장 넓은 자식이 가질 수 있는 최댓값, 최솟값에 관한 정보를 부모에게 제공한다. 부모는 이를 이용해 자식이 필요로 하는 크기에 기반해 크기에 관한 결정을 내릴 수 있다.
  • 다음은 내재적 크기 정보에 기반해 Row 컴포저블의 높이를 설정하는 코드 예시다.
Row(modifier.height(IntrinsicSize.Min)) {

}

Column(modifier.width(IntrinsicSize.Max)) {

}
  • 위의 컴포저블을 렌더링하면 Row 높이는 가장 큰 자식을 표시할 수 있는 최소 높이로 설정되고 Column의 폭은 가장 폭이 넓은 자식의 최대 가능 폭으로 설정된다.
  • 반대로 모디파이어가 없다면 Row나 Column 같은 레이아웃 컴포저블은 전령적으로 그 부모가 설정한 이용할 수 있는 모든 공간을 차지하는 크기로 설정된다.

내재적 최대 및 최소 크기 측정값

  • 한 행의 텍스트를 표시하는 Text 컴포저블의 최대 폭은 그 컴포저블이 표시하는 텍스트의 길이와 같다. 이것은 IntrinsicSize의 Max 값과 같다.
This is a Text composable containing a line of text
  • 하지만 Text 컴포넌트는 여러 행의 텍스트를 표시할 수도 있다. 높이 제한이 없다고 가정하면, 이 경우 Text 컴포넌트가 필요로 하는 최소 폭은 텍스트 문자열에서 가장 긴 단어의 길이와 같게 된다. 이 값은 IntrinsicSize의 Min 값과 같다.
This is a 
Text 
composable 
containing 
a line of 
text
  • 이때 Text 컴포넌트의 높이 제한이 적용되면 제한된 높이에 텍스트를 다 넣어야 하기 때문에 가로 폭이 길어질 수 있고 이렇게 되면 IntrinsicSize의 Min값이 달라질 수 있다.
This is a Text 
composable 
containing a line 
of text

IntrinsicDemo 코드 완성하기

@Composable
fun MainScreen() {
    var textState by remember { mutableStateOf("") }

    val onTextChange = { text: String ->
        textState = text
    }

    Column(
        Modifier
            .width(200.dp)
            .padding(5.dp)) {
        Column {
            Text(modifier = Modifier
                .padding(start = 4.dp),
                text = textState
            )

            Box(
                Modifier
                    .height(10.dp)
                    .fillMaxWidth()
                    .background(Color.Blue))
        }
        MyTextField(text = textState, onTextChange = onTextChange)
    }
}

@Composable
fun MyTextField(text: String, onTextChange: (String) -> Unit) {
    TextField(
        value = text,
        onValueChange = onTextChange
    )
}

프로젝트 테스트하기

  • 에뮬레이터를 이용해서 앱을 실행한 뒤, TextField에 임의의 텍스트를 입력해본다.
  • Box는 텍스트의 폭이 아닌 최상위 Column의 폭까지 증가한다.

IntrinsicSize.Max 측정값 적용하기

  • 현재 목표는 Box의 폭을 텍스트에 맞추는 것이다. 이를 위해서는 Text와 Box를 포함하는 Column의 폭이 그 자식들의 내재적 최대 측정값에 따라 설정되도록 하면 된다.
    Column(
        Modifier
            .width(200.dp)
            .padding(5.dp)) {
        Column(Modifier.width(IntrinsicSize.Max)) { // 수정한 부분
            Text(modifier = Modifier
                .padding(start = 4.dp),
                text = textState
            )

            Box(
                Modifier
                    .height(10.dp)
                    .fillMaxWidth()
                    .background(Color.Blue))
        }
        MyTextField(text = textState, onTextChange = onTextChange)
    }

  • 이제 Box의 폭과 입력한 텍스트의 폭이 일치하게 된다.
  • 텍스트를 삭제하거나 추가하는 경우에도 Box의 폭이 그에 맞추어 변경된다. 이는 문자가 입력 또는 삭제될 때마다 재구성에 의해 부모 Column의 폭이 변하기 때문이다.

IntrinsicSize.Min 적용하기

  • IntrinsicSize.Min을 사용하기 위해 위의 코드를 다음과 같이 수정한다.
    Column(
        Modifier
            .width(200.dp)
            .padding(5.dp)) {
        Column(Modifier.width(IntrinsicSize.Min)) { // 수정한 부분
            Text(modifier = Modifier
                .padding(start = 4.dp),
                text = textState
            )

            Box(
                Modifier
                    .height(10.dp)
                    .fillMaxWidth()
                    .background(Color.Blue))
        }
        MyTextField(text = textState, onTextChange = onTextChange)
    }
  • 앞의 테스트에서 이용한 것보다 좀 더 긴 문장을 입력해 본다.
  • 위의 수정에 따라 Column의 최소 폭은 표시되는 가장 긴 단어의 폭과 일치하게 된다.

정리

  • 가장 빠른 속도로 렌더링하기 위해 컴포즈는 재구성 과정에서 컴포저블의 크기를 단 한 번만 측정한다. 그러나 이는 부모가 자식의 크기를 측정하기 전에 크기 설정에 관한 결정을 내려야 할 때 문제를 일으킬 가능성이 있다.
  • 모든 컴포저블은 내용이 잘리거나 가려지는 것에 관계없이 해당 콘텐츠를 편안하게 렌더링할 수 있는 내재적 최대 및 최소 크기를 갖는다. IntrinsicSize를 이용할 경우 부모는 자식을 스캔하면 폭과 높이의 최솟값 및 최댓값을 알아낼 수 있으며, 이 정보를 이용해 크기를 설정할 수 있다.
profile
안녕하세요.

0개의 댓글