// namesList.kt
val names = listOf(
"Kaylie Grant",
"Leon Ventura",
"Keanu Alvarado"
).groupBy {
it.first()
}.toSortedMap()
-------------------------------------------------------------
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val namesList = names.map {
Category(
name = it.key.toString(),
items = it.value
)
}
setContent {
CategorizedLazyColumnTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
CategorizedLazyColumn(
categories = namesList
)
}
}
}
}
}
data class Category(
val name: String,
val items: List<String>
)
@Composable
private fun CategoryHeader(
text: String,
modifier: Modifier = Modifier
) {
Text(
text = text,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
modifier = modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.primaryContainer)
.padding(16.dp)
)
}
@Composable
private fun CategoryItem(
text: String,
modifier: Modifier = Modifier
) {
Text(
text = text,
fontSize = 14.sp,
modifier = modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.background)
.padding(16.dp)
)
}
@Composable
private fun CategorizedLazyColumn(
categories: List<Category>,
modifier: Modifier = Modifier
) {
LazyColumn(modifier) {
categories.forEach { category ->
stickyHeader {
CategoryHeader(category.name)
}
items(category.items) { text ->
CategoryItem(text)
}
}
}
}
names
의 결과는 주어진 리스트를 첫 번째 문자(이름의 첫 글자)를 기준으로 그룹화한 뒤, 정렬된 Map이다.
groupBy { it.first() }
는 이름의 첫 번째 문자(it.first()
)를 기준으로 각 이름을 그룹화한다.
그 후 toSortedMap()
을 사용하여 이 그룹을 알파벳 순으로 정렬된 맵 형태로 변환한다.
val names = listOf(
"Kaylie Grant",
"Leon Ventura",
"Keanu Alvarado"
).groupBy {
it.first()
}.toSortedMap()
groupBy { it.first() }
:
it.first()
는 각 이름의 첫 번째 문자를 가져온다.
groupBy
는 이 첫 번째 문자를 기준으로 이름들을 그룹화한다.
"Kaylie Grant"
→ 첫 글자: "K"
"Leon Ventura"
→ 첫 글자: "L"
"Keanu Alvarado"
→ 첫 글자: "K"
이로 인해 다음과 같이 그룹화된다.
{
K = ["Kaylie Grant", "Keanu Alvarado"],
L = ["Leon Ventura"]
}
toSortedMap()
:
toSortedMap()
은 결과를 키 기준으로 알파벳 순으로 정렬된 맵으로 변환한다.K
가 L
보다 먼저 온다.{
K = ["Kaylie Grant", "Keanu Alvarado"],
L = ["Leon Ventura"]
}
val namesList = names.map {
Category(
name = it.key.toString(),
items = it.value
)
}
여기서 map을 사용하면, 각 키(K, L), 값 리스트를 Category 객체로 변환한다.
it.key = K
, it.value = ["Kaylie Grant", "Keanu Alvarado"]
Category(name = "K", items = listOf("Kaylie Grant", "Keanu Alvarado"))
it.key = L
, it.value = ["Leon Ventura"]
Category(name = "L", items = listOf("Leon Ventura"))
namesList
결과listOf(
Category(name = "K", items = listOf("Kaylie Grant", "Keanu Alvarado")),
Category(name = "L", items = listOf("Leon Ventura"))
)
@Composable
private fun CategorizedLazyColumn(
categories: List<Category>,
modifier: Modifier = Modifier
) {
LazyColumn(modifier) {
categories.forEach { category ->
stickyHeader {
CategoryHeader(category.name)
}
items(category.items) { text ->
CategoryItem(text)
}
}
}
}
이 함수는 이름 목록을 첫 글자별로 그룹화하여 리스트 형태로 표시한다.
LazyColumn을 사용하고,
각 카테고리의 헤더(첫 글자)는 스크롤 시 상단에 고정(stickyHeader) 되도록 구현되었다.
1. 이름을 첫 글자별로 그룹화한 categories 리스트를 받아서 LazyColumn을 사용하여 렌더링
2. 각 카테고리의 첫 글자를 stickyHeader로 추가하여 스크롤 시 상단에 고정
3. 각 카테고리에 속한 이름들을 CategoryItem으로 나열
4. 결과적으로 "K" 그룹에는 K로 시작하는 이름들이, "L" 그룹에는 L로 시작하는 이름들이 표시됨
5. 스크롤하면 현재 카테고리의 첫 글자가 상단에 고정되며, 다음 카테고리로 넘어갈 때 바뀜
Column
버전 스크롤 가능
많은 데이터를 효율적으로 관리
항목을 동적으로 추가 및 제거 가능
Row
버전 가로 방향 스크롤 지원
스크롤 가능한 아이템이 필요할 때 사용
수평으로 많은 항목을 표시하는 경우 유용
LazyColumn {
stickyHeader {
Text("Header 1", modifier = Modifier.fillMaxWidth().background(Color.Gray))
}
items(listOf("Item A", "Item B", "Item C")) { item ->
Text(text = item, modifier = Modifier.padding(16.dp))
}
}
스크롤 시 헤더가 상단에 고정됨
그룹화된 목록을 만들 때 유용
LazyColumn 내에서만 동작 (LazyRow에서는 지원하지 않음)
기능 | LazyColumn | LazyRow | Sticky Header |
---|---|---|---|
방향 | 세로(Vertical) | 가로(Horizontal) | LazyColumn 내에서 특정 헤더 고정 |
사용 예시 | 일반 리스트, 뉴스 피드 | 이미지 갤러리, 가로 스크롤 리스트 | 카테고리별 목록, 연락처 리스트 |
스크롤 | 위/아래 스크롤 가능 | 좌/우 스크롤 가능 | 헤더가 상단에 고정됨 |
주요 특징 | 많은 데이터를 효율적으로 처리 | 가로 스크롤 지원 | 그룹화된 데이터 표시 시 유용 |
LazyRow, LazyColumn을 사용하면
화면에 보이는 항목만 렌더링하기 때문에,
메모리 낭비를 최소화하고 성능을 최적화할 수 있다!
참고한 영상 출처)
https://www.youtube.com/watch?v=XfYlRn_Jy1g&t=52s