当前位置: 首页 > news >正文

Compose笔记(十四)--LazyColumn

        这一节了解一下Compose中的LazyColumn,在Jetpack Compose 中,LazyColumn 是一个用于高效显示长列表或可滚动垂直布局的组件。它类似于传统 Android 开发中的 RecyclerView,但专为 Compose 的声明式 UI 框架设计,能够显著优化性能,特别是在处理大量数据时。

特点

1 惰性加载(Lazy Loading)
LazyColumn 仅渲染当前屏幕上可见的列表项,未显示的部分不会被加载,从而减少内存占用和初始化时间。
2 高效性能
通过按需渲染和复用已加载的组件,LazyColumn 在处理大数据集时表现优异,避免了传统布局(如 Column)因一次性加载所有项而导致的性能问题。
3 声明式 API
使用 Compose 的声明式语法,开发者可以通过简单的代码定义列表项的布局和行为,无需手动管理适配器或视图持有者(ViewHolder)。

与RecyclerView的对比

LazyColumn一般场景
长列表或大数据集:如聊天记录、商品列表、新闻 feed 等。
动态内容更新:需要频繁更新列表项的场景。
复杂布局:需要嵌套其他 Compose 组件的列表。

栗子

import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

//显示简单列表
@Composable
fun SimpleListExample() {
    val itemsList = listOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5")
    LazyColumn {
        items(itemsList) { item ->
            Text(text = item)
        }
    }
}
// 键值(Key)支持
//通过为每个项指定唯一的键值,可以优化列表更新时的性能。

items(items, key = { it.id }) { item ->
    Text(text = item.name)
}
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp


//带有头和尾的列表

@Composable
fun ListWithHeaderAndFooterExample() {
    val itemsList = listOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5")
    LazyColumn {
        item {
            Text(text = "Header", modifier = Modifier.padding(16.dp))
        }
        items(itemsList) { item ->
            Text(text = item, modifier = Modifier.padding(16.dp))
        }
        item {
            Text(text = "Footer", modifier = Modifier.padding(16.dp))
        }
    }
}
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

sealed class ListItem {
    data class TextItem(val text: String) : ListItem()
    data class HeaderItem(val title: String) : ListItem()
}


//不同类型的列表项
@Composable
fun ListWithDifferentItemTypesExample() {
    val itemsList = listOf(
        ListItem.HeaderItem("Section 1"),
        ListItem.TextItem("Item 1"),
        ListItem.TextItem("Item 2"),
        ListItem.HeaderItem("Section 2"),
        ListItem.TextItem("Item 3"),
        ListItem.TextItem("Item 4")
    )
    LazyColumn {
        items(itemsList) { item ->
            when (item) {
                is ListItem.HeaderItem -> {
                    Text(text = item.title, modifier = Modifier.padding(16.dp))
                }
                is ListItem.TextItem -> {
                    Text(text = item.text, modifier = Modifier.padding(16.dp).padding(start = 32.dp))
                }
            }
        }
    }
}
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier


//分页加载列表
@Composable
fun PaginationListExample() {
    var itemsList by remember { mutableStateOf((1..10).toList()) }
    val listState = rememberLazyListState()
    val loadMore = remember {
        derivedStateOf {
            val layoutInfo = listState.layoutInfo
            val totalItemsNumber = layoutInfo.totalItemsCount
            val lastVisibleItemIndex = (layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0) + 1
            lastVisibleItemIndex > totalItemsNumber - 2
        }
    }

    LaunchedEffect(loadMore.value) {
        if (loadMore.value) {
            val newItems = (itemsList.last() + 1..itemsList.last() + 10).toList()
            itemsList = itemsList + newItems
        }
    }

    LazyColumn(state = listState) {
        items(itemsList) { item ->
            Text(text = "Item $item")
        }
    }
}
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

// 模拟数据类
data class Item(val name: String)

// 分模块加载
@Composable
fun LazyColumnWithModules() {
    val moduleBData = listOf(
        Item("Item 1"),
        Item("Item 2"),
        Item("Item 3")
    )

    LazyColumn(
        contentPadding = PaddingValues(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        // 模块 A
        item {
            ModuleA()
        }

        // 模块 B
        item {
            ModuleB(moduleBData)
        }

        // 模块 C
        item {
            ModuleC()
        }
    }
}

@Composable
fun ModuleA() {
    Box(
        modifier = Modifier
           .fillMaxWidth()
           .background(Color.LightGray)
           .padding(16.dp)
    ) {
        Text(text = "Module A")
    }
}

@Composable
fun ModuleB(data: List<Item>) {
    Column(
        modifier = Modifier
           .fillMaxWidth()
           .clip(RoundedCornerShape(16.dp))
           .background(Color.Gray)
           .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        data.forEach { item ->
            Box(
                modifier = Modifier
                   .fillMaxWidth()
                   .background(Color.White)
                   .border(1.dp, Color.Black, RoundedCornerShape(8.dp))
                   .padding(16.dp)
            ) {
                Text(text = item.name)
            }
        }
    }
}

@Composable
fun ModuleC() {
    Box(
        modifier = Modifier
           .fillMaxWidth()
           .background(Color.LightGray)
           .padding(16.dp)
    ) {
        Text(text = "Module C")
    }
}

注意

1 避免过度嵌套
在 LazyColumn 中嵌套其他 LazyColumn 或复杂布局可能导致性能问题。
2 状态管理
如果列表项包含状态(如复选框、输入框等),建议将状态提升到外部以避免不必要的重组。

简单看一下LazyColumn源码

1. LazyColumn 函数定义
LazyColumn 本质上是一个 Composable 函数,其定义位于 androidx.compose.foundation.lazy 包下。下面是简化后的函数:

@Composable
fun LazyColumn(
    modifier: Modifier = Modifier,
    state: LazyListState = rememberLazyListState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    content: LazyListScope.() -> Unit
) {
    LazyList(
        modifier = modifier,
        state = state,
        contentPadding = contentPadding,
        reverseLayout = reverseLayout,
        verticalArrangement = verticalArrangement,
        horizontalAlignment = horizontalAlignment,
        flingBehavior = flingBehavior,
        orientation = Orientation.Vertical,
        content = content
    )
}

分析:
modifier:用于修饰 LazyColumn 的外观和行为,例如设置大小、边距、背景等。
state:LazyListState 类型,用于管理列表的滚动状态,如滚动位置、滚动偏移量等。
contentPadding:PaddingValues 类型,用于设置列表内容的内边距。
reverseLayout:布尔类型,若为 true,列表将从底部开始反向布局。
verticalArrangement:Arrangement.Vertical 类型,用于指定列表项在垂直方向上的排列方式,如顶部对齐、居中对齐等。
horizontalAlignment:Alignment.Horizontal 类型,用于指定列表项在水平方向上的对齐方式,如左对齐、居中对齐等。
flingBehavior:FlingBehavior 类型,用于定义列表在快速滑动时的滚动行为。
content:LazyListScope.() -> Unit 类型,这是一个作用域函数,用于定义列表的内容,即列表项的具体布局

2. LazyList 函数调用
LazyColumn内部调用了LazyList 函数,LazyList是一个更通用的列表组件,支持垂直和水平滚动。以下是 LazyList函数的简化:

@Composable
private fun LazyList(
    modifier: Modifier = Modifier,
    state: LazyListState = rememberLazyListState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    orientation: Orientation,
    content: LazyListScope.() -> Unit
) {
    // 实现逻辑
}

分析:
orientation:Orientation 类型,指定列表的滚动方向,LazyColumn 中传入的是 Orientation.Vertical。

3. 懒加载机制实现
LazyColumn 的核心特性是懒加载,即只有当列表项进入可视区域时才会进行渲染。这一机制主要通过 LazyListState 和 LazyListLayout 来实现。
3.1 LazyListState
LazyListState 用于管理列表的滚动状态,包括滚动位置、滚动偏移量等。它内部维护了一个 LayoutInfo 对象,用于记录列表项的布局信息。通过 LazyListState,可以实现滚动到指定位置、监听滚动事件等功能。
3.2 LazyListLayout
LazyListLayout 是 LazyColumn 的布局实现类,它继承自 Layout 组件。在 LazyListLayout 中,会根据当前的滚动状态和可视区域,计算需要渲染的列表项,并调用相应的 Composable 函数进行渲染。具体实现逻辑如下:
测量阶段:根据列表项的大小和滚动状态,计算需要渲染的列表项的数量和位置。
布局阶段:将需要渲染的列表项布局到可视区域内,并根据滚动状态进行偏移。

4. 列表项管理
LazyColumn 通过 LazyListScope 来管理列表项。LazyListScope 提供了多个方法,用于添加不同类型的列表项,例如 items、item 等。
4.1 items 方法
items 方法用于添加一组相同类型的列表项,其简化如下:

fun <T> LazyListScope.items(
    items: List<T>,
    key: ((item: T) -> Any)? = null,
    contentType: ((item: T) -> Any)? = null,
    itemContent: @Composable LazyItemScope.(item: T) -> Unit
)

 分析:
items:列表数据,即需要显示的列表项集合。
key:可选参数,用于为每个列表项提供一个唯一的键,以提高列表的性能和稳定性。
contentType:可选参数,用于指定列表项的类型,以便在渲染时进行优化。
itemContent:Composable 函数,用于定义每个列表项的具体布局。

4.2 item 方法
item 方法用于添加单个列表项,其简化如下:

fun LazyListScope.item(
    key: Any? = null,
    contentType: Any? = null,
    content: @Composable LazyItemScope.() -> Unit
)

分析:
key:可选参数,用于为列表项提供一个唯一的键。
contentType:可选参数,用于指定列表项的类型。
content:Composable 函数,用于定义列表项的具体布局。

简单总结,LazyColumn 的源码主要围绕懒加载机制和列表项管理展开。通过 LazyListState 和 LazyListLayout 实现了懒加载,只有在列表项进入可视区域时才进行渲染,从而提高了性能。同时,通过 LazyListScope 提供的方法,可以方便地管理不同类型的列表项。

相关文章:

  • 计算机系统---性能指标(1)CPU与GPU
  • 横扫SQL面试——PV、UV问题
  • 语法: i8=make8( var, offset);
  • 3D Gaussian Splatting as MCMC 与gsplat中的应用实现
  • Python面向对象-开闭原则(OCP)
  • Access:在移动互联网与AI时代焕发新生
  • ReFormX:现代化的 React 表单解决方案 - 深度解析与最佳实践
  • sojson。v5:新一代JavaScript代码保护工具的技术解析与应用场景
  • 代码随想录回溯算法03
  • Spring 中的 IOC
  • Unet网络的Pytorch实现和matlab实现
  • 洛谷每日1题-------Day37__P1634 禽兽的传染病
  • Xorg 内存上涨的根源探究
  • 存储引擎 / 事务 / 索引
  • 实操(多线程特点、健壮性降低、缺乏访问控制)Linux
  • Django和Celery实现的异步任务案例
  • 小学诗词大会竞赛活动实施方案
  • Qwen-Agent框架的文件相关操作:从Assistant到BasicDocQA
  • 《比特城传奇:公钥、私钥与网络安全的守护之战》
  • 【Mac 从 0 到 1 保姆级配置教程 11】- Mac 基础配置 Finder、触控板、常用快捷键等
  • 网站开发周期是什么意思/网络链接推广
  • 苏州互联网公司工资/上海官网seo
  • 在深圳市住房和建设局网站/拉新工作室在哪里接项目
  • 传媒有限公司/百度seo快速见效方法
  • 做网站的经历感想/微信管理系统软件
  • 大众汽车网站建设/长春网站建设开发