今天大概會聊到的範圍
- LazyColumn
- StickyHeader
基本的畫面可以顯示了,但在 Android App 的開發中,我們很常需要顯示大量的資料:商品列表、景點列表、好友列表...。顯示列表可以說是 App UI 的基本功。
我們都知道可以使用 RecyclerView
來實現列表。在這個過程中,我們需要透過 Adapter 將資料 "adapt" 成畫面 ( 一個一個 view item )。並且,為了讓 View 可以重複使用、為了讓 findViewById
可以不要重複呼叫而造成浪費,我們需要 ViewHolder
來乘載 View 相關的元素,再透過 bind (onBindViewHolder
) 將資料與 ViewHolder (view 本身)結合在一起。最後,為了讓列表中可以有多種個不同的項目,我們會用 viewType 來分辨,並用不同的 View 將這些 item 分開顯示。
在 Compose 中,顯示由上而下的元件自然會想到 Column
。其實最簡單的列表顯示就是透過 Column
,在 Column
中透過 for
迴圈其實就可以產生出一個列表
@Composable
fun ListView() {
Column(...) {
repeat(20) {
ChildView()
}
}
}
但是這樣的列表並無法處理 Scolling 等行為,且會一次性的全部 render 出來。
在 Compose 中,有另一個工具更適合使用,那就是 Lazy composable。Lazy composable 最常見的有 LazyColumn
和 LazyRow
,可以想像成縱向和橫向的 RecyclerView。
以 LazyColumn
為例:
@Composable
fun ListView() {
LazyColumn(...) {
// 這個區塊是 LazyListScope
item { Item() }
}
在 LazyColumn
的 trailing lambda 中是一個 LazyListScope
。在 LazyListScope
中有三個常用的 function 來增加 item。
@Composable
fun ListView() {
LazyColumn(...) {
// 1. item { }
item { Header() }
// 2. items(count) { }
items(20) { index ->
Item()
}
// 3. items(data) { it -> }
items(data) { Item(it)}
}
}
第一種方法就是 item
,這個 function 可以增加單一個 Composable function 到 List 中。很適合用在 header 、footer 這種只出現一次,和別人都長得不一樣的項目上。這取代了以往需要將 header 、footer 硬轉成與列表同一個型別,並且塞進 RecyclerView Adapter 中,再用 viewType 將其分開的過程。或是可以省去使用較複雜的工具 (如 Epoxy )
第二種方式是 items(count)
,這個 function 可以單純的重複多次 item view。算是很單純產生大量資料的方式。在 items 的 lambda 中可以取得 index ,可以用來當作取得資料的依據。
第三個可能也是最常用的一種方式是 items(data)
,將已經處理成 List 的 data list 放進 items ,在 lambda 中取得單一一個 data 並且將其轉成 Composable 並顯示
在使用 item
/ items
時,除了要顯示的內容之外,還可以提供一個 key
。
items(
items = data,
key = { item -> item.id }
) {
Item(it)
}
這個 key 可以用來標明每個 item 的 id。若在 user 滑動之後有 data change,畫面上的第一個項目將會保持是同一個 key 的項目。
另外分享一個有趣的功能,我們可以將任何一個 item 用 stickyHeader
取代。如此,當那個 item 滑動到最頂端時,就會停留在上方。
一個 LazyColumn 中也可以使用多個 stickyHeader
,當每一個 stickyHeader
滑動到最上面時,都會取代前一個 stickyHeader
。
LazyColumn() {
stickyHeader {
// ...
}
item { ... }
}
Reference: