外观
ListItem — 通用列表项
单张卡片式的列表行:左边一个图标容器,中间标题 + 副标题,右边最多两个图标操作或一个自定义插槽。
基本用法
最简形式:
kotlin
ListItem(
title = "清理缓存",
subtitle = "当前占用 128 MB",
icon = Phosphor.Broom,
onClick = { /* … */ },
)右侧放操作按钮:
kotlin
ListItem(
title = "下载目录",
subtitle = "/storage/emulated/0/Download",
icon = Phosphor.Folder,
actionIcon1 = Phosphor.PencilSimple,
onAction1Click = { /* 重命名 */ },
actionIcon2 = Phosphor.Trash,
onAction2Click = { /* 删除 */ },
)右侧放任意内容(开关、箭头、计数):
kotlin
ListItem(
title = "自动保存",
icon = Phosphor.Gear,
trailing = {
Switch(checked = autoSave, onCheckedChange = { autoSave = it })
},
)用图片当左侧图标:
kotlin
ListItem(
title = "示例图片",
iconUrl = "https://example.com/cover.jpg",
onClick = { /* … */ },
)参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | String | — | 标题,单行、超长省略 |
modifier | Modifier | Modifier | 修饰符 |
subtitle | String? | null | 副标题,最多两行、超长省略。空白字符串等同于不传 |
icon | ImageVector? | null | 左侧图标(与 iconUrl 二选一) |
iconUrl | String? | null | 左侧图片 URL,Coil 加载、ContentScale.Crop |
iconBackgroundColor | Color | primaryContainer | 图标容器底色 |
iconTint | Color | onPrimaryContainer | 图标颜色 |
actionIcon1 | ImageVector? | null | 右侧第一个图标按钮 |
actionIcon1Tint | Color | onSurfaceVariant | 第一个图标颜色 |
onAction1Click | (() -> Unit)? | null | 第一个图标点击 |
actionIcon2 | ImageVector? | null | 右侧第二个图标按钮 |
actionIcon2Tint | Color | onSurfaceVariant | 第二个图标颜色 |
onAction2Click | (() -> Unit)? | null | 第二个图标点击 |
trailing | @Composable (() -> Unit)? | null | 自定义右侧插槽,优先级高于 actionIcon1 / actionIcon2 |
onClick | (() -> Unit)? | null | 整行点击。传 null 时整行不可点 |
要点
icon和iconUrl只给一个。 两个都传时只有icon生效(iconUrl那个分支进不去)。两个都不给,左侧整块不渲染,标题会顶到 20dp 内边距上。trailing一旦传了,actionIcon1/actionIcon2全部失效 —— 代码是if (trailing != null) … else …。想在自定义插槽旁边再放一个图标按钮,自己在trailing里排。- 图标按钮必须 icon 和 click 同时给。 判断条件是
actionIcon1 != null && onAction1Click != null,只给图标不会渲染出来。这是防呆:避免画出一个「点了没反应」的按钮。 onClick = null时整行不可点 —— 内部走Surface(enabled = onClick != null),所以不只是「点了没反应」,连水波纹和按压态都没有。纯展示的行就不用传。- 别用
modifier覆盖尺寸。 图标容器 48dp、右侧按钮 40dp 都是标定过的值。 subtitle传空串和传null效果一样(内部用isNullOrBlank()判)。
说明
- 图标容器 48dp:原来的 42dp 是「差一点到触控标准」的尴尬尺寸;48dp 同时满足视觉重量和 M3 的最小触控尺寸。
- 内边距 20 / 16:比常见的 16 / 12 更从容,一屏之内不拥挤优先于「一屏多塞一行」。
- 标题用
titleMedium、副标题用bodySmall:标题该比正文更重。两者都带省略号,超长不会撑破布局。 - 标题与副标题之间是 3dp,紧凑但不粘。
trailing插槽前自带 12dp 间距,自己不用再补。- 形状是
AppShapes.row、底色透明:单行本身不画背景,放进什么容器就融进什么容器。想要卡片质感,自己在外层给background+clip。