D07 / 怎麽显示大量资料 - Lazy composables ( LazyColumn & StickyHeader )

今天大概会聊到的范围

  • 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 最常见的有 LazyColumnLazyRow,可以想像成纵向和横向的 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 并显示

Key

在使用 item / items 时,除了要显示的内容之外,还可以提供一个 key

items(
    items = data,
    key = { item -> item.id }
) {
    Item(it)
}

这个 key 可以用来标明每个 item 的 id。若在 user 滑动之後有 data change,画面上的第一个项目将会保持是同一个 key 的项目。

StickyHeader

另外分享一个有趣的功能,我们可以将任何一个 item 用 stickyHeader 取代。如此,当那个 item 滑动到最顶端时,就会停留在上方。

一个 LazyColumn 中也可以使用多个 stickyHeader,当每一个 stickyHeader 滑动到最上面时,都会取代前一个 stickyHeader

LazyColumn() {
    stickyHeader {
       // ...
    }
    item { ... }    
}

Reference:


<<:  初探编码的世界,Ruby 30 天刷题修行篇第六话

>>:  [Day 6]从零开始学习 JS 的连续-30 Days---判断流程

Day17 CSS Media Query

在了解Media Queries的用法之前,先来了解一些RWD的观念吧。 RWD是什麽? RWD是...

[Day19] 逻辑运算子

逻辑运算子(Logical Operators) 常用来判断多个条件并回传结果,有 &&am...

Day 25:推销自己

前言 为什麽推销自己很重要呢,在这个竞争的市场中,需要有一些东西来证明自己的身价。 在我搜寻 And...

DAY3: Node.js安装环境

今天主要会说明Nodejs环境的安装, 可以选择在自己熟悉或是喜好的编辑器上进行操作。 首先安装No...

战略思考与规划(Strategic Thinking and Planning)

使命与愿景(Mission and Vision) .一个组织不是无缘无故存在的。它是为目的而建立...