11월 1주차에는 KMP에 대한 내용 외에는 간단한 것들을 만들어보는 기사들이 재밌는것들이 있었습니다.
이 기사는 리스트 선택 창의 애니메이션에 대한 글입니다.
https://composable-fun.ghost.io/list-sections-with-animated-shapes/
소개
이 글은 Jetpack Compose를 사용하여 애니메이션 형태가 있는 리스트 섹션을 만드는 방법에 대한 글입니다. 이 튜토리얼에서는 체크된 아이템과 체크되지 않은 아이템을 시각적으로 구분하고, 아이템이 위치를 변경할 때 모서리 크기를 애니메이션으로 처리하는 방법을 설명합니다. 평범한 기초용 글이구나 했는데 애니메이션에서 모서리의 변화에 놀래서 한 번 만져보고 싶다고 생각했습니다.
내용
1. 모델 정의
- Todo와 ListElement로 이루어진 모델을 정의합니다. Todo는 간단한 데이터(이름과 체크 상태)를 나타내고, ListElement는 리스트 아이템의 시각적 표현을 담당합니다.
- ListElement는 Header와 Item 두 가지 유형이 있으며, Item은 Top, Middle, Bottom, Single의 네 가지 역할(Role)로 구분됩니다.
data class Todo(
val id: String = UUID.randomUUID().toString(),
val text: String,
val isChecked: Boolean,
)
sealed interface ListElement {
val id: String
data class Header(val text: String) : ListElement {
override val id = text
}
data class Item(val todo: Todo, val role: Role) : ListElement {
override val id = todo.id
}
enum class Role {
TOP, BOTTOM, MIDDLE, SINGLE
}
}
2. 섹션 데이터 처리
- Todo 목록을 Section 목록으로 변환하는 과정을 거칩니다. 각 Section은 헤더와 Todo 목록을 포함합니다.
- 이를 통해 LazyColumn에 적합한 형태로 데이터를 조직화합니다.
data class Section(
val header: String?,
private val todos: List<Todo>
) {
val todosWithRoles = todos.associateWith { todo ->
when {
todos.size == 1 -> Role.SINGLE
todos.indexOf(todo) == 0 -> Role.TOP
todos.indexOf(todo) == todos.size - 1 -> Role.BOTTOM
else -> Role.MIDDLE
}
}
}
3. 리스트 렌더링
- LazyColumn을 사용하여 리스트를 렌더링합니다. ListElement 유형에 따라 HeaderItem과 TodoItem으로 렌더링이 분기됩니다.
- TodoItem 클릭 시 해당 Todo의 체크 상태가 토글됩니다.
LazyColumn {
items(items = listItems, key = { it.id }) { item ->
when (item) {
is ListElement.Header -> HeaderItem(text = item.text)
is ListElement.Item -> TodoItem(todo = item.todo, role = item.role)
}
}
}
4. 애니메이션 추가
- Modifier.animateItemPlacement()를 사용하여 리스트 아이템의 위치 변경에 애니메이션을 적용합니다.
- ListElement.Role.toShape() 메서드를 수정하여 아이템의 모서리 크기에 애니메이션을 추가합니다.
TodoItem(
modifier = Modifier.animateItemPlacement(),
todo = todoItem.todo,
role = todoItem.role
)
5. 추가 애니메이션 구현
- 애니메이션은 리스트 아이템 간의 간격과 내부 모서리에도 적용됩니다.
- animateDpAsState를 사용하여 LazyColumn 내의 아이템 간격을 애니메이션화합니다.
LazyColumn(verticalArrangement = Arrangement.spacedBy(spacedBy)) {
// 아이템들
}
6. 성능 고려사항
- 재구성(recomposition) 횟수를 줄이는 방법에 대한 고려사항을 제시합니다. 하지만 코드의 가독성과 사용성을 최우선으로 생각하며, 성능 문제가 눈에 띄지 않는 한 최적화에 집중하지 않는 것을 권장합니다.
7. 전체 소스코드
https://gist.github.com/KlassenKonstantin/502ab8969124c073812531533418e329
정리
글에서 설명한 이런 사소한 애니메이션 모델링이 생각보다 UI 인 "멋"의 정점인것 같습니다.
간략하게 클론코딩해보니 생각보다 손이 많이 가는 개발이였습니다.
유튜브에서 동영상을 저장할때 리스트에서 조금 불편함을 느꼈는데 이러한 방식으로 만들지 않는 이유는 뭘까 한 번 생각해보게 되는 글이였습니다.
'Android Weekly' 카테고리의 다른 글
Android Weekly #-597 "안드로이드 메모리 개선 - Runtime 업데이트" (0) | 2023.12.12 |
---|---|
Android Weekly #-596 "Android 앱 배포 전 6단계 확인과정" (0) | 2023.12.12 |
Android Weekly #-594 "Jetpack Compose의 modifier의 변화 역사?" (0) | 2023.12.12 |
Android Weekly #-593 "안드로이드 14의 주요 변경 사항" (0) | 2023.12.11 |
Android Weekly #-592 "더쉬운 network mocking on Android" (0) | 2023.12.08 |