Android Compose UI 清單 (Lazy List)
App 中最常見的介面就是清單。在 Compose 中,我們不使用 RecyclerView,而是使用更簡單強大的 Lazy List。
「Lazy」的意思是懶加載:它只會繪製螢幕上可見的項目。這對於成千上萬筆資料的清單來說,效能至關重要。
垂直清單 (LazyColumn)
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp), // 清單四周的留白
verticalArrangement = Arrangement.spacedBy(8.dp) // 項目之間的間距
) {
// 1. 單個項目
item {
Text("Header", style = MaterialTheme.typography.titleLarge)
}
// 2. 多個項目 (固定數量)
items(5) { index ->
Text("Item $index")
}
// 3. 多個項目 (來自 List 資料)
val names = listOf("Alice", "Bob", "Charlie")
items(names) { name ->
Text("Hello $name")
}
}
水平清單 (LazyRow)
用法與 LazyColumn 幾乎一模一樣,只是方向不同。
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(10) {
Card { ... }
}
}
Key 的重要性
當清單資料會發生變動(新增、刪除、排序)時,提供唯一的 key 非常重要。這能幫助 Compose 識別該項目,避免不必要的重組,並保持捲動位置。
items(
items = userList,
key = { user -> user.id } // 使用唯一 ID 作為 Key
) { user ->
UserRow(user)
}
捲動控制 (LazyListState)
透過 rememberLazyListState,我們可以控制或監聽清單的捲動位置。
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
// 顯示 "回到頂端" 按鈕
val showButton = listState.firstVisibleItemIndex > 0
if (showButton) {
FloatingActionButton(
onClick = {
scope.launch {
listState.animateScrollToItem(0) // 平滑捲動到頂端
}
}
) {
Icon(Icons.Filled.KeyboardArrowUp, contentDescription = null)
}
}
LazyColumn(state = listState) { ... }
Sticky Headers (黏性標題)
在聯絡人清單中,常見滑動時 "A", "B", "C" 的分組標題會吸附在頂端。LazyColumn 內建支援這個功能。
val grouped = contacts.groupBy { it.name.first() }
LazyColumn {
grouped.forEach { (initial, contactsForInitial) ->
stickyHeader {
Text(
text = initial.toString(),
modifier = Modifier
.fillMaxWidth()
.background(Color.LightGray)
.padding(8.dp)
)
}
items(contactsForInitial) { contact ->
ContactItem(contact)
}
}
}
小結
LazyColumn 是 RecyclerView 的完美替代品。它不需要 Adapter,不需要 ViewHolder,程式碼量減少了 90% 以上,寫起來非常愉悅。