Android Weekly

Android Weekly #-595 "리스트 선택 창의 애니메이션"

베블렌 2023. 12. 12. 01:36

11월 1주차에는 KMP에 대한 내용 외에는 간단한 것들을 만들어보는 기사들이 재밌는것들이 있었습니다.

이 기사는 리스트 선택 창의 애니메이션에 대한 글입니다.

 

https://composable-fun.ghost.io/list-sections-with-animated-shapes/

 

How to create list sections with animated shapes

Welcome to Composable fun, a place where I will share tutorials, hints, dos and don'ts, learnings, new developments but also questions I encounter on the subject of Jetpack Compose. I'll try to let the code and visuals speak, with me filling in the gaps. S

composable-fun.ghost.io

 

 

 

소개

이 글은 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

 

List sections

List sections. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

 

 

 

정리

글에서 설명한 이런 사소한 애니메이션 모델링이 생각보다 UI 인 "멋"의 정점인것 같습니다.

간략하게 클론코딩해보니 생각보다 손이 많이 가는 개발이였습니다.

유튜브에서 동영상을 저장할때 리스트에서 조금 불편함을 느꼈는데 이러한 방식으로 만들지 않는 이유는 뭘까 한 번 생각해보게 되는 글이였습니다.

 

 

 

 

https://androidweekly.net/

 

Android Weekly - Free weekly Android & Kotlin development newsletter

Android Weekly - Free weekly Android & Kotlin development newsletter

androidweekly.net