@Composable
fun MessageList(messages: List<Message>) {
Column {
messages.forEach { message ->
MessageRow(message)
}
}
}
- 스크롤이 필요하지 않은 경우 (방향에 따라) 간단한 Column 또는 Row 를 사용하여 다음과 같이 목록을 반복하여 각 항목의 콘텐츠를 내보낼 수 있다.
- verticalScroll() 수정자를 사용하여 Column 을 스크롤 가능하게 만들 수 있다.
@Composable
fun MessageList(messages: List<Message>) {
val scrollState = rememberScrollState()
Column(modifier = Modifier.verticalScroll(scrollState)) {
messages.forEach { message ->
MessageRow(message)
}
}
}
지연 목록
- 많은 수의 항목이나 길이를 알 수 없는 목록을 표시해야 하는 경우 Column 과 같은 레이아웃을 사용하면 모든 항목이 표시 가능 여부와 관계없이 구성되고 배치되므로 성능 문제가 발생할 수 있다.
- Compose 는 구성요소의 표시 영역에 표시되는 항목만 구성하여 배치하는 구성요소 집합을 제공한다. 이러한 구성요소에는 LazyColumn 및 LazyRow 가 포함된다.
- 지연 구성요소는 @Composable 콘텐츠 블록 구성요소를 수락하고 앱에서 직접 컴포저블을 내보낼 수 있도록 허용하는 대신 LazyListScope.() 블록을 제공한다.
- 이 *LazyListScope 블록은 앱에서 항목 콘텐츠를 설명할 수 있는 DSL 을 제공한다.
LazyListScope DSL
LazyColumn {
// 1. 단일 아이템 추가
item {
Text(text = "First item")
}
// 2. 5개 아이템 추가
items(5) { index ->
Text(text = "Item: $index")
}
// 3. 아이템 컬렉션 추가
items(messages) { message ->
MessageRow(message)
}
// 4. 각 아이템에 대한 인덱스와 내용 제공
itemsIndexed(messages) { index, message ->
MessageRowIndexed(index, message)
}
}
지연 그리드
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 128.dp)
) {
items(photos) { photo ->
PhotoItem(photo)
}
}
- LazyVerticalGrid 및 LazyHorizontalGrid 컴포저블은 그리드로 항목 표시를 지원한다.
- 지연 세로 그리드는 여러 열에 걸쳐 세로로 스크롤 가능한 컨테이너에 항목을 표시하는 반면, 지연 가로 그리드는 가로축을 중심으로 동일하게 동작한다.
- 그리는 목록과 동일한 강력한 API 기능을 가지며 콘텐츠를 설명하기 위한 매우 유사한 DSL(LazyGridScope.())을 사용한다.
- LazyVerticalGrid 의 Column 매개변수와 LazyHorizontalGrid 의 row 매개변수는 셀이 열이나 행으로 형성되는 방식을 제어한다.
- GridCells.Adaptive : 각 셀에 최소한 minSize 공간이 있고 모든 추가 공간이 균등하게 분산된다는 조건 하에 가능한 한 많은 행이나 열로 구성된 그리드를 정의한다.
- 예시) LazyVerticalGrid.Adaptive(20.dp)는 가능한 한 많은 열이 있고 모든 열이 최소 20.dp 이며 동일한 너비를 갖는다. 화면 너비가 88.dp 이면 각각 22.dp 인 열이 4개 있다.
- 남은 너비는 열 수가 계산된 후 열 간에 균등하게 분배된다.
- 이러한 적응형 크기 조절 방법은 다양한 화면 크기에서 항목 집합을 표시하는 데 유용하다.
- 디자인에서 특정 항목만 비표준 측정기준이 있어야 하는 경우 그리드 지원을 사용하여 항목에 맞춤 열 스팬을 제공할 수 있다.
- LazyGridScope DSL item 및 items 메서드의 span 매개변수를 사용하여 열 스팬을 지정한다.
- 스팬 범위의 값 중 하나인 maxLineSpan 은 적응형 크기 조절을 사용할 때 유용하다.
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 30.dp)
) {
item(span = {
GridItemSpan(maxLineSpan)
}) {
CategoryCard("Fruits")
}
}
지연 시차 그리드
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Adaptive(200.dp),
verticalItemSpacing = 4.dp,
horizontalArrangement = Arrangement.spacedBy(4.dp),
content = {
items(randomSizedPhotos) { photo ->
AsyncImage(
model = photo,
contentScale = ContentScale.Crop,
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
)
}
},
modifier = Modifier.fillMaxSize()
)
- LazyVerticalStaggeredGrid 및 LazyHorizontalStaggeredGrid 는 지연 로드된 비슷한 간격의 항목 그리드를 만들 수 있는 컴포저블이다.
- 지연 세로 지그재그형 그리드는 여러 열에 걸쳐 세로로 스크롤 가능한 컨테이너에 항목을 표시하며, 개별 항목의 높이를 다르게 지정할 수 있다. 지연된 가로 그리드는 너비가 다른 항목이 있는 가로축에서 동일한 동작을 보인다.
- 고정된 수의 열을 설정하려면 StaggeredGridCells.Adaptive 대신 StaggeredGridCells.Fixed(columns) 를 사용하면 된다.
콘텐트 패딩
LazyColumn(
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
) { ... }
- 콘텐츠 가장자리 주변에 패딩을 추가해야 하는 경우가 있다.
- 지연 구성요소를 사용하면 일부 paddingValues 을 contentPadding 매개변수에 전달하여 이 작업을 지원할 수 있다.
콘텐츠 간격
LazyColumn(
verticalArrangement = Arrangement.spacedBy(4.dp),
) { ... }
LazyRow(
horizontalArrangement = Arrangement.spacedBy(4.dp),
) { ... }
LazyVerticalGrid(
columns = GridCells.Fixed(2),
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
items(photos) { item ->
PhotoItem(item)
}
}
- 항목 사이에 간격을 추가하려면 Arrangement.spacedBy() 를 사용한다.
- 그리드는 세로 및 가로 정렬을 모두 허용한다.
항목 키
- 기본적으로 각 항목의 상태는 목록이나 그리드에 있는 항목의 위치를 기준으로 키가 지정된다.
- 하지만 이 경우 위치를 효율적으로 변경하는 항목에 상태가 저장되지 않아 데이터 세트가 변경되면 문제가 발생할 수 있다. LazyColumn 내 LazyRow 시나리오의 경우 행에서 항목 위치가 변경되면 사용자가 행 내에서 스크롤 위치를 잃게 된다.
LazyColumn {
items(
items = messages,
key = { message ->
message.id
}
) { message ->
MessageRow(message)
}
}
- 이 문제를 해결하려면 각 항목에 안정적이고 고유한 키를 제공하여 key 매개변수에 블록을 제공해야 한다. 안정적인 키를 제공하면 데이터 세트가 변경되어도 항목 상태의 일관성이 유지된다.
LazyColumn {
items(books, key = { it.id }) {
val rememberedValue = remember {
Random.nextInt()
}
}
}
- 키를 제공하면 Compose 가 재정렬을 올바르게 처리할 수 있다. 예를 들어, 항목에 저장된 상태가 포함되어 있는 경우 키를 설정하면 위치가 변경될 때 Compose 가 항목과 함께 이 상태를 옮길 수 있다.
LazyColumn {
items(books, key = {
// primitives, enums, Parcelable, etc.
}) {
// ...
}
}
- 하지만 항목 키로 사용할 수 있는 유형에는 한 가지 제한사항이 있다. 키 유형은 Activity 가 다시 생성될 때 상태를 유지하는 Android의 메커니즘인 Bundle 에서 지원해야 한다. Bundle 은 primitives, enum, Parcelable 과 같은 유형을 지원한다.
LazyColumn {
items(books, key = { it.id }) {
val rememberedValue = rememberSaveable {
Random.nextInt()
}
}
}
- Activity 가 다시 생성될 때 또는 이 항목에서 스크롤하여 벗어났다가 다시 스크롤하여 돌아올 때도 항목 컴포저블 내의 rememberSaveable 을 복원할 수 있도록 키를 Bundle 에서 지원해야 한다.
항목 애니메이션
- 맞춤 애니메이션 사양을 제공할 수 있다. (animateItem 수정자)
고정 헤더(실험용)
- '고정 헤더' 패턴은 그룹화된 데이터 목록을 표시할 때 유용하다. (stickyHeader())
스크롤 위치에 반응
- 많은 앱이 스크롤 위치와 항목 레이아웃 변경사항에 반응하고 이를 수신 대기해야 한다. 지연 구성요소는 LazyListState 를 호이스팅하여 이 사용 사례를 지원한다.
- LazyListState 는 firstVisibleItemIndex 및 firstVisibleItemScrollOffset 속성을 제공한다.
스크롤 위치 제어
- LazyListState 는 스크롤 위치를 '즉시' 스냅하는 scrollToItem() 및 애니메이션을 사용하여 스크롤하는(부드럽게 스크롤하는) animateScrollToItem() 함수를 통해 이 기능을 지원한다.
큰 데이터 세트(페이징)
@Composable
fun MessageList(pager: Pager<Int, Message>) {
val lazyPagingItems = pager.flow.collectAsLazyPagingItems()
LazyColumn {
items(
lazyPagingItems.itemCount,
key = lazyPagingItems.itemKey { it.id }
) { index ->
val message = lazyPagingItems[index]
if (message != null) {
MessageRow(message)
} else {
MessagePlaceholder()
}
}
}
}
- Paging 라이브러리를 사용하면 앱에서 큰 항목 목록을 지원하며 필요에 따라 작은 목록을 로드하고 표시할 수 있다.
- 페이징된 콘텐츠 목록을 표시하려면 collectAsLazyPagingItems() 확장 함수를 사용한 다음 반환된 LazyPagingItems 를 LazyColumn 의 items() 에 전달하면 된다.
'안드로이드 > Compose' 카테고리의 다른 글
[Compose] TextField에서 엔터키 사용하기 (0) | 2024.11.21 |
---|---|
[Compose] TextField에 오류 메시지 표시하기 (0) | 2024.11.03 |
[Compose] TextField password 보이기/숨기기 (0) | 2024.11.03 |