Composable 함수들을 실행시키며 이전에도 몇번 나온 트리구조를 생성한다.
이 UI Tree는 layout node로 이루어져있으며 이 노드들은 다음 단계에서 필요로하는 정보들을 가지고 있다.
DFS 방식으로 노드를 탐방하며 각 노드의 사이즈와 위치를 계산한다
세가지 알고리즘에 따라 동작한다.
1. 자식 사이즈 측정 -> DFS방식이 여기서 나온다 해당 노드의 자식노드를 끝가지 타고 내려가며 계산한다.
2. 사이즈 결정 -> 1단계에서 이루어진 자식들의 사이즈들을 기반으로 노드의 사이즈를 계산한다.
3. 위치 -> 크기계산이 끝난 노드들을 정책에 맞춰 배치한다. (measurePolicy)
위 작업이 끝나면 각 노드는 width, height 크기와 x, y를 가지게 된다.
다시 UI Tree 맨 위에서부터 내려오면서 스크린에 픽셀을 찍는다.

컴포지션 결과에 따라 Layout phase, Drawing Phase를 실행할 수 있으며, 콘텐츠 + 크기 + 레이아웃이 이전 값과 동일하면 스킵된다.
Layout Phase는 2단계로 나누어진다.
1. measure -> 사이즈를 측정하는 단계, Moidifer.measure과 같은 메소드들을 통해 실행됨
2. place -> 실제 화면에 배치하는 단계, Modifier.offset과 같은 메소드들을 통해 실행됨
measure, place는 각 별개의 범위를 가져서 measure이 변경되었다고해서 place를 다시 호출하지는 않는다.
Canvas, Modifier.drawBehind, Modifier.drawWithContent등을 통해 이루어진다.
상태값이 변경되면 그리기 단계만 실행한다.

Composition 단계에서 컨텐츠가 변경되었다면 ->
Layout 실행 ->
사이즈 또는 포지션이 달라지면 ->
Draw 실행
과 같이 진행된다.
기본적으로 컴포지션에 관련된 파라미터들이 변경되면 리컴포지션이 일어난다. 그렇지만 호출시기를 조정함에 따라 불필요한 리컴포지션을 방지할 수 있다.
Box {
val listState = rememberLazyListState()
Image(
// ...
// Non-optimal implementation!
Modifier.offset(
with(LocalDensity.current) {
// State read of firstVisibleItemScrollOffset in composition
(listState.firstVisibleItemScrollOffset / 2).toDp()
}
)
)
LazyColumn(state = listState) {
// ...
}
}
위의 예는 스크롤이 일어날 때마다 Composition Phase에서 리컴포지션이 일어나게 된다.
하지만 람다를 제공하는 방식으로 변경하면
Box {
val listState = rememberLazyListState()
Image(
// ...
Modifier.offset {
// State read of firstVisibleItemScrollOffset in Layout
IntOffset(x = 0, y = listState.firstVisibleItemScrollOffset / 2)
}
)
LazyColumn(state = listState) {
// ...
}
}
레이아웃 단계 특히 place 단계에서 호출됨으로 Composition phase에서는 값을 읽지않음으로 Layout, Drawing phase에 대한 리컴포지션만 실행하면 된다.
위에서 나온 3가지 phase들은 반드시 순서를 지켜 실행되어야만한다.
만약 A레이아웃의 크기를 계산한 뒤 해당 크기를 이용해 B 레이아웃을 계산하고 싶은 경우
onSizeChagned, onGlobal~~ 과 같은 함수를 이용하면 제대로된 동작을 보장하지 않을 수 있고 A layout phase -> B composeition 과 같은 권장되지 않는 구조를 만들 수 있다.
따라서 이런 경우 customLayout을 생성해야한다.
Modifier.Layout을 이용하는 방법, Layout()을 구현하는 방법, SubcomposeLayout을 사용하는 방법이 있다.
최소 하나의 레이아웃이 다른 레이아웃의 측정값을 이용해야하는 경우에 사용하면 좋다.