👋 哈喽大家好,欢迎回到Compose零基础系列~ 前四篇咱们一步步搞定了环境搭建、静态UI、样式控制,还有最核心的状态管理,现在简单的交互页面已经能轻松写出来了。
但咱们做开发,肯定绕不开一个场景——列表展示。比如手机里的消息列表、商品列表、联系人列表,这些都是最常用的UI。以前用传统View开发,写列表就得用RecyclerView,又是写Adapter、又是写ViewHolder,还要处理复用,麻烦得不行,新手很容易卡在这里。
而Compose直接给咱们简化到极致,用 LazyColumn(垂直列表)和 LazyRow(水平列表),几行代码就能搞定一个高性能列表,不用写Adapter、不用管复用,新手也能一键上手。
本篇作为系列第五篇,全程用大白话讲透LazyColumn和LazyRow,不搞复杂概念,所有知识点都搭配实战案例,代码可直接复制运行,学完你就能彻底抛弃RecyclerView,轻松写出各种列表页面。
本篇核心目标:搞懂LazyColumn/LazyRow和RecyclerView的区别;掌握LazyColumn(垂直列表)的基本用法、item写法;学会LazyRow(水平列表)的使用;掌握列表点击、分割线、间距设置;实战一个商品列表,搞定日常开发中80%的列表场景;避开新手写列表的常见坑。
🔗 前文回顾:上一篇咱们重点学了状态管理,用remember和mutableStateOf实现了数据联动,这一篇咱们就用状态管理+列表组件,实现一个能交互、能展示的完整列表,建议按系列顺序学,前后衔接更顺,理解起来也更轻松哦!
一、先搞懂:为什么不用RecyclerView?LazyColumn好在哪?
很多新手可能会问,我已经会用RecyclerView了,为什么还要学LazyColumn?这里我用大白话跟大家说清楚,对比一下,你就知道LazyColumn有多香了:
- RecyclerView(传统写法) :要写Adapter、ViewHolder,还要处理数据绑定、item复用、点击事件,代码量大,新手容易写错,比如复用导致的UI错乱,排查起来很麻烦。
- LazyColumn/LazyRow(Compose写法) :不用写Adapter、不用写ViewHolder,直接用item包裹列表项,几行代码就能搞定;自动实现item复用(和RecyclerView的复用逻辑一样,性能不打折);点击事件、分割线、间距,直接用Modifier就能设置,简单又高效。
简单总结一句话:LazyColumn就是Compose版本的“简化版RecyclerView”,功能一样强,写法更简单,新手友好度拉满。而且它的名字里有个“Lazy”,意思是“懒加载”——只有当item进入屏幕时,才会创建和渲染,不会一次性加载所有item,性能和RecyclerView一样好,甚至更优。
补充一句:LazyColumn对应垂直列表(上下滑动),LazyRow对应水平列表(左右滑动),用法基本一致,咱们重点讲LazyColumn,LazyRow跟着学就会了。
二、核心用法:LazyColumn 基础入门(最常用)
LazyColumn的用法非常简单,核心就是“LazyColumn包裹item,item里写列表项的UI”,咱们从最基础的“静态列表”开始,一步步来,代码带详细注释,新手能直接复制运行。
2.1 最基础的静态列表(无交互)
先写一个最简单的垂直列表,展示10个文本item,看看LazyColumn的基本结构:
@Composable
fun BasicLazyColumnDemo() {
// 垂直列表:LazyColumn,默认上下滑动
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp) // 列表整体边距
) {
// 循环创建10个item(列表项)
items(10) { index ->
// 每个item的UI:这里用Text展示索引
Text(
text = "列表项 ${index + 1}",
fontSize = 16.sp,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp) // 每个item的上下间距
)
}
}
}
✅ 效果说明:运行后,会显示一个垂直列表,有10个文本项,上下滑动流畅,每个item之间有8dp的间距,列表整体有16dp的边距。
这里有两个核心点,新手一定要记住:
- items(n) :n是列表的长度,这里写10,就会循环创建10个item;lambda里的index是当前item的索引(从0开始),所以我们用index+1展示“列表项 1”到“列表项 10”。
- item里写UI:每个item就是一个独立的组件,你可以写Text、Image、Button,甚至是复杂的卡片,和咱们前几篇学的组件、布局完全兼容。
2.2 绑定数据源(真实开发场景)
真实开发中,我们不会用固定的10个item,而是绑定一个数据源(比如List集合),咱们用一个“商品列表”的模拟数据,演示如何绑定数据源:
// 1. 先定义一个商品数据类(真实开发中,数据来自接口)
data class Goods(
val id: Int,
val name: String, // 商品名称
val price: String // 商品价格
)
@Composable
fun LazyColumnWithDataDemo() {
// 2. 模拟数据源:3个商品
val goodsList = listOf(
Goods(1, "小米14", "¥4999"),
Goods(2, "华为Mate 60", "¥5999"),
Goods(3, "iPhone 15", "¥6999")
)
// 3. 垂直列表,绑定数据源
LazyColumn(
modifier = Modifier.fillMaxWidth()
) {
// 绑定list:items(数据源),lambda里的item就是当前商品
items(goodsList) { goods ->
// 每个item的UI:商品卡片(用Row水平排列)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.background(Color.White)
.shadow(2.dp, RoundedCornerShape(8.dp))
.padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
// 商品名称
Text(
text = goods.name,
fontSize = 16.sp,
modifier = Modifier.weight(1f) // 占满剩余宽度
)
// 商品价格(红色加粗)
Text(
text = goods.price,
fontSize = 16.sp,
color = Color.Red,
fontWeight = FontWeight.Bold
)
}
}
}
}
✅ 效果说明:运行后,会显示3个商品卡片,每个卡片包含商品名称和价格,卡片有阴影、圆角,上下滑动流畅,和真实开发中的商品列表完全一致。
💡 小贴士:这里用到了我们前几篇学的Row布局、Modifier样式,还有数据类,可见前后知识点是连贯的,只要跟着系列学,就能一步步积累,不用单独记新东西。
2.3 列表点击事件(常用交互)
列表item肯定要支持点击(比如点击商品进入详情页),LazyColumn的点击事件很简单,直接给item的Modifier加clickable就好,咱们基于上面的商品列表,添加点击事件:
@Composable
fun LazyColumnWithClickDemo() {
val goodsList = listOf(
Goods(1, "小米14", "¥4999"),
Goods(2, "华为Mate 60", "¥5999"),
Goods(3, "iPhone 15", "¥6999")
)
LazyColumn(
modifier = Modifier.fillMaxWidth()
) {
items(goodsList) { goods ->
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.background(Color.White)
.shadow(2.dp, RoundedCornerShape(8.dp))
.padding(12.dp)
// 给item添加点击事件
.clickable {
// 点击逻辑:这里模拟跳转详情页,打印商品名称
Log.d("LazyColumnDemo", "点击了商品:${goods.name}")
},
verticalAlignment = Alignment.CenterVertically
) {
Text(text = goods.name, fontSize = 16.sp, modifier = Modifier.weight(1f))
Text(text = goods.price, fontSize = 16.sp, color = Color.Red, fontWeight = FontWeight.Bold)
}
}
}
}
✅ 效果说明:点击任意一个商品卡片,都会打印对应的商品名称,真实开发中,这里可以写跳转详情页的逻辑,和我们前几篇学的点击事件用法完全一样。
三、LazyRow 用法(水平列表,左右滑动)
LazyRow和LazyColumn用法几乎完全一样,唯一的区别是:LazyColumn是垂直列表(上下滑动),LazyRow是水平列表(左右滑动),咱们用一个“标签列表”演示,代码直接复用前面的逻辑:
@Composable
fun LazyRowDemo() {
// 模拟标签数据源
val tagList = listOf("推荐", "热点", "科技", "娱乐", "体育", "财经", "汽车", "美食")
// 水平列表:LazyRow,默认左右滑动
LazyRow(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
// 水平间距:item之间的间距
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(tagList) { tag ->
// 每个标签的UI:圆角背景、居中文本
Text(
text = tag,
fontSize = 14.sp,
color = Color.White,
modifier = Modifier
.background(Color(0xFF6200EE), RoundedCornerShape(20.dp))
.padding(horizontal = 12.dp, vertical = 6.dp)
// 标签点击事件
.clickable {
Log.d("LazyRowDemo", "点击了标签:$tag")
}
)
}
}
}
✅ 效果说明:运行后,会显示一个水平标签栏,左右滑动可以查看所有标签,每个标签有圆角背景,点击标签会打印标签名称,和我们平时刷APP看到的标签栏完全一致。
这里重点说一个LazyRow的常用属性:horizontalArrangement = Arrangement.spacedBy(8.dp) ,作用是设置每个item之间的水平间距,不用再给每个item加padding,更简洁,LazyColumn也可以用verticalArrangement设置垂直间距。
四、实战:完整商品列表(综合案例)
结合前面的知识点,我们做一个完整的商品列表实战,包含:垂直列表、商品卡片、点击事件、分割线、列表间距,还有状态管理(模拟加载更多),完全贴合真实开发场景,代码可直接复制运行:
@Composable
fun CompleteGoodsListDemo() {
// 1. 用状态管理,模拟商品列表数据(可动态添加,模拟加载更多)
var goodsList by remember {
mutableStateOf(
listOf(
Goods(1, "小米14", "¥4999"),
Goods(2, "华为Mate 60", "¥5999"),
Goods(3, "iPhone 15", "¥6999"),
Goods(4, "OPPO Find X7", "¥4499"),
Goods(5, "vivo X100", "¥4299")
)
)
}
// 2. 完整的商品列表
LazyColumn(
modifier = Modifier.fillMaxSize(),
// 列表item之间的垂直间距
verticalArrangement = Arrangement.spacedBy(12.dp),
// 列表整体边距
contentPadding = PaddingValues(16.dp)
) {
// 商品列表item
items(goodsList) { goods ->
GoodsItem(goods = goods) {
// 点击商品的回调:这里模拟跳转详情页
Log.d("GoodsList", "进入商品详情:${goods.name}")
}
}
// 底部加载更多item(模拟加载状态)
item {
Text(
text = "加载更多...",
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
// 模拟加载更多逻辑:添加3个新商品
val newGoods = listOf(
Goods(6, "三星S24", "¥5799"),
Goods(7, "荣耀Magic6", "¥4599"),
Goods(8, "一加Ace 3", "¥2799")
)
goodsList = goodsList + newGoods
},
textAlign = TextAlign.Center,
color = Color(0xFF6200EE)
)
}
}
}
// 抽取商品item组件,复用(工程开发常用)
@Composable
fun GoodsItem(goods: Goods, onItemClick: () -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.shadow(4.dp, RoundedCornerShape(12.dp))
.padding(16.dp)
.clickable { onItemClick() }, // 点击事件通过回调传递
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
// 商品名称
Text(
text = goods.name,
fontSize = 18.sp,
fontWeight = FontWeight.Medium
)
// 商品价格
Text(
text = goods.price,
fontSize = 18.sp,
color = Color.Red,
fontWeight = FontWeight.Bold
)
}
}
✅ 实战效果说明:
- 列表整体有16dp边距,每个商品卡片之间有12dp间距,卡片有阴影、圆角,样式精致;
- 点击任意商品卡片,会打印商品名称,模拟跳转详情页;
- 列表底部有“加载更多”文本,点击后会添加3个新商品,实现动态加载(用到了我们上一篇学的状态管理);
- 抽取了GoodsItem组件,实现复用,符合工程开发规范,和我们第三篇学的Modifier复用逻辑一致。
五、新手写列表的常见避坑指南
第五篇避坑重点:写列表看似简单,但新手很容易踩坑,尤其是复用和性能问题,以下5个坑提前避开,少走弯路
- 用Column代替LazyColumn:很多新手会用Column包裹循环的item写列表,这样会一次性加载所有item,数据多的时候(比如100条),会卡顿、占用大量内存,正确做法是用LazyColumn(懒加载)。
- 忘记加contentPadding:想给列表整体加边距,直接给LazyColumn加padding,会导致滑动时,顶部和底部的item被遮挡,正确做法是用contentPadding设置列表内边距。
- item间距设置繁琐:给每个item加padding设置间距,不如用LazyColumn的verticalArrangement = Arrangement.spacedBy(),更简洁、更规范。
- 不抽取item组件:把item的UI写在LazyColumn里面,代码冗余、难以维护,正确做法是抽取成独立的组件(比如我们实战中的GoodsItem),方便复用和修改。
- 混淆LazyColumn和Column的滑动:Column本身不能滑动,需要加verticalScroll才能滑动,而LazyColumn默认就能滑动,不需要额外加滚动修饰符。
六、本篇总结 + 下篇预告
6.1 本篇核心收获
- 搞懂了LazyColumn/LazyRow和RecyclerView的区别:用法更简单,不用写Adapter,性能一样好。
- 掌握了LazyColumn(垂直列表)的基本用法:items绑定数据源、item写UI、添加点击事件。
- 学会了LazyRow(水平列表)的用法:和LazyColumn基本一致,用于左右滑动的标签、横向列表。
- 通过完整商品列表实战,掌握了列表间距、分割线、加载更多、组件复用的技巧,能应对日常开发中80%的列表场景。
- 避开了新手写列表的常见坑,知道了LazyColumn的懒加载优势,避免卡顿问题。
6.2 下篇内容预告
本篇我们学会了列表组件,能实现各种列表展示,但现在我们写的UI,样式比较单一,比如按钮颜色、文本样式、卡片圆角,都是固定的,想统一修改很麻烦。下一篇我们将学习:第六篇:Material3主题、样式与自定义主题,学会统一管理APP的颜色、字体、形状,让你的APP样式更规范、更美观,还能轻松切换深色模式。
七、系列更新进度(建议收藏追更)
- 第一篇:零基础入门,环境搭建+第一个Compose页面(已更新)
- 第二篇:基础组件+三大核心布局,实战简单UI(已更新)
- 第三篇:Modifier修饰符全解,UI样式灵活控制(已更新)
- 第四篇:Compose状态管理核心(remember、mutableStateOf)(已更新)
- 第五篇:LazyColumn、LazyRow 实战,彻底替代RecyclerView(当前)
- 第六篇:Material3主题、样式与自定义主题
- 第七篇:导航组件Navigation Compose
- 第八篇:ViewModel+Compose架构实战
- 第九篇:Compose动画基础与常用交互
- 第十篇:综合实战:仿写简单常用页面,吃透全流程
本篇的实战案例,建议大家一定要动手敲一遍,尤其是完整商品列表,里面用到了前面几篇的知识点,能帮你巩固记忆、融会贯通。如果文章对你有帮助,欢迎点赞、收藏、关注三连,评论区留下你的学习疑问或遇到的问题,下篇主题样式内容正在加急更新,带你继续吃透Compose核心~