5、Jetpack Compose 入门 --- 延迟可组合项

139 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 5 天,点击查看活动详情

假设你有一组大量的列表项数据,如果使用Column的话,不论该列表项是否正显示在屏幕中,系统均会对其进行绘制,因此很有可能会出现性能问题。

为了解决这个问题,Compose提供了LazyColumn组件,只有当列表项在视图中可见时,它才会对其中的组件进行绘制。当然,与此对应的,还有一个横向的延迟可组合项组件LazyRow

参数

@Composable
fun LazyColumn(
    modifier: Modifier = Modifier,
    state: LazyListState = rememberLazyListState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical = if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    content: LazyListScope.() -> Unit
)
参数类型描述可选值
modifierModifier修饰符
stateLazyListState用来控制或观察列表状态的状态对象含有两个属性:
1. firstVisibleItemIndex:第一个可见项的索引
2. firstVisibleItemScrollOffset:第一个可见项的滚动偏移量
contentPaddingPaddingValues列表项的内容内边距
reverseLayoutBoolean是否反转布局true:从底部开始布局
false:从顶部开始布局
verticalArrangementArrangement.Vertical列表项的垂直安排。
可在列表项之间添加间隔,以及在不足以填满最小尺寸时的排列方式
horizontalAlignmentAlignment.Horizontal列表项的水平位置
flingBehaviorFlingBehaviorfling行为的处理逻辑
contentLazyListScope.() -> Unit描述内容注意:LazyColumn跟其他的布局不同,它的content需要的不是一个@Composable块,而是一个LazyListScope()

LazyListScope

@LazyScopeMarker
interface LazyListScope {
    /**
     * 添加单个item
     */
    fun item(key: Any? = null, content: @Composable LazyItemScope.() -> Unit)

    /**
     * 添加指定数量的item
     */
    fun items(
        count: Int,
        key: ((index: Int) -> Any)? = null,
        itemContent: @Composable LazyItemScope.(index: Int) -> Unit
    )

    /**
     * 添加粘性标题
     */
    @ExperimentalFoundationApi
    fun stickyHeader(key: Any? = null, content: @Composable LazyItemScope.() -> Unit)
}

/**
 * 添加一组item
 *
 * @param items 数据集合
 * @param key 标识item的key
 * @param itemContent 单个item的内容
 */
inline fun <T> LazyListScope.items(
    items: List<T>,
    noinline key: ((item: T) -> Any)? = null,
    crossinline itemContent: @Composable LazyItemScope.(item: T) -> Unit
) = items(items.size, if (key != null) { index: Int -> key(items[index]) } else null) {
    itemContent(items[it])
}

/**
 * 添加一组item
 *
 * @param items 数据集合
 * @param key 标识item的key
 * @param itemContent 单个item的内容
 */
inline fun <T> LazyListScope.itemsIndexed(
    items: List<T>,
    noinline key: ((index: Int, item: T) -> Any)? = null,
    crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit
) = items(items.size, if (key != null) { index: Int -> key(index, items[index]) } else null) {
    itemContent(it, items[it])
}

/**
 * 添加一组item
 *
 * @param items 数据集合
 * @param key 标识item的key
 * @param itemContent 单个item的内容
 */
inline fun <T> LazyListScope.items(
    items: Array<T>,
    noinline key: ((item: T) -> Any)? = null,
    crossinline itemContent: @Composable LazyItemScope.(item: T) -> Unit
) = items(items.size, if (key != null) { index: Int -> key(items[index]) } else null) {
    itemContent(items[it])
}

/**
 * Adds an array of items where the content of an item is aware of its index.
 *
 * @param items 数据集合
 * @param key 标识item的key
 * @param itemContent 单个item的内容
 */
inline fun <T> LazyListScope.itemsIndexed(
    items: Array<T>,
    noinline key: ((index: Int, item: T) -> Any)? = null,
    crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit
) = items(items.size, if (key != null) { index: Int -> key(index, items[index]) } else null) {
    itemContent(it, items[it])
}

举例

联系人列表

GIF 2022-3-16 1-12-31.gif

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ContactList() {
    val list = listOf(
        Pair("JY", "觉远"),
        Pair("WS", "无色"),
        Pair("HZD", "何足道"),
        ...
        Pair("YBH", "杨不悔"),
        Pair("CYC", "常遇春"),
        Pair("ZYZ", "朱元璋")
    ).sortedBy { it.first }.groupBy { it.first.first().toString() }
    LazyColumn(content = {
        list.forEach { (key, dataList) ->
            stickyHeader {
               ...
               Text(text = key, ...)
               ...
            }
            items(items = dataList) {
               ...
               Text(text = it.second, ...)
               ...
            }
        }
    })
}