일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- boj
- textfield
- android
- 백준
- livedata
- ProGuard
- Python
- 프로그래머스
- Compose
- 암호학
- MyVoca
- Rxjava
- activity
- relay
- Gradle
- AWS
- Kotlin
- Codeforces
- MiTweet
- 쿠링
- androidStudio
- pandas
- architecture
- 코루틴
- Coroutines
- TEST
- Hilt
- GitHub
- 코드포스
- Coroutine
- Today
- Total
이동식 저장소
[Compose] Movable Content 본문
Composition 단계에서 UI 트리의 내용을 옮길 수 있다면 많은 이득을 얻을 수 있다. Recomposition 과정 속에서 composable을 다시 만들지 않고 그대로 옮김으로써 내부 상태를 보존할 수 있기 때문이다. 다음 코드를 보자.
@Composable
fun MyApplication() {
if (Mode.current == Mode.Landscape) {
Row {
Tile1()
Tile2()
}
} else {
Column {
Tile1()
Tile2()
}
}
}
``Mode``의 값이 바뀌면 ``Tile1()``과 ``Tile2()`` 내부의 모든 값이 초기화된다. 하지만 tile 두 개를 하나의 composition 묶음으로 생각하면 어떨까?
@Composable
fun MyApplication() {
val tiles = remember {
movableContentOf {
Tile1()
Tile2()
}
}
if (Mode.current == Mode.Landscape) {
Row { tiles() }
} else {
Column { tiles() }
}
}
이렇게 하면 ``Tile1()``과 ``Tile2()``이 온전히 재사용되므로 내부의 상태 역시 보존된다.
Movable content의 movable은 UI 트리에서 composable을 원래 상태 그대로 자유롭게 움직일 수 있음을 뜻한다.
또다른 사용 예시
Movable content를 잘 사용하면 미묘한 성능 및 로직 이슈를 해결할 수 있다. 다음 코드를 보자.
@Composable
fun <T> NaiveTwoColumns(items: List<T>, composeItem: @Composable (item: T) -> Unit) {
val half = items.size / 2
Row {
Column {
for (item in items.take(half)) {
composeItem(item)
}
}
Column {
for (item in items.drop(half)) {
composeItem(item)
}
}
}
}
``items``를 두 개의 열로 나누어 배치하는 코드이다. 이 코드의 문제점은 ``items``이 하나만 바뀌어도 ``NaiveTwoColumns`` 전체가 recomposition된다는 점이다. 마찬가지로 ``composeItem(item)``도 모두 다시 실행되고, 내부 상태가 모두 사라지게 된다.
``item``에 key를 설정하면 될까?
@Composable
fun <T> KeyedTwoColumns(items: List<T>, composeItem: @Composable (item: T) -> Unit) {
val half = items.size / 2
Row {
Column {
for (item in items.take(half)) {
key(item) {
composeItem(item)
}
}
}
Column {
for (item in items.drop(half)) {
key(item) {
composeItem(item)
}
}
}
}
}
Key를 설정하면 불필요한 recomposition을 대폭 줄일 수 있다. 하지만 아직 문제가 완전히 해결되지 않았다. 두 ``Column`` 사이에 key가 공유되지 않기 때문이다.
``movableContentOf`` 함수를 사용하면 UI 트리에서 아이템을 다시 만드는 대신 위치만 바꿀 수 있고, 따라서 내부 상태도 보존된다.
@Composable
fun <T> ComposedTwoColumns(items: List<T>, composeItem: @Composable (item: T) -> Unit) {
val half = items.size / 2
val composedItems =
items.map { item -> item to movableContentOf { composeItem(item) } }.toMap()
Row {
Column {
for (item in items.take(half)) {
composedItems[item]?.invoke()
}
}
Column {
for (item in items.drop(half)) {
composedItems[item]?.invoke()
}
}
}
}
마지막으로 ``composedItems``를 적절히 remember하기만 하면 recomposition이 발생해도 아이템과 내부 상태를 보존할 수 있다. ``List<T>``의 확장 함수로 완성하면 다음과 같다.
fun <T> List<T>.movable(
transform: @Composable (item: T) -> Unit
): @Composable (item: T) -> Unit {
val composedItems = remember(this) { mutableMapOf<T, () -> Unit>() }
return { item: T -> composedItems.getOrPut(item) { movableContentOf { transform(item) } } }
}
사용 예시는 다음과 같다.
NaiveTwoColumns(items, items.movable { ItemContent(it) })
공부하면서 보니 생각보다 쓸 일이 많지는 않을 듯하다. 그래도 알아두면 좋으니까.
참고
'Primary > Compose' 카테고리의 다른 글
Figma 컴포넌트를 Compose로 변환????? (0) | 2022.10.26 |
---|---|
[Compose] 반응형 앱 구현 실전 (4) | 2022.10.20 |
Compose가 UI를 그리는 과정 (0) | 2022.08.13 |
Compose Example - sunflower (1) | 2022.08.02 |
Compose의 Stability에 관하여 (0) | 2022.07.05 |