【共创季稿事节】鸿蒙原生 ArkTS 布局精讲:Column 与 Divider 搭配,分隔线的最佳实践
鸿蒙原生 ArkTS 布局精讲:Column 与 Divider 搭配,分隔线的最佳实践
一、前言
在移动端应用开发中,「列表页」是最常见、最高频的界面形态之一。无论是系统设置、消息通知、联系人列表还是订单管理,几乎每个应用都离不开纵向列表。然而,列表页的设计难点不在于「把它们排出来」,而在于「如何让视觉层次清晰可辨」。
很多开发者初学 ArkTS 时,习惯用 Column 一股脑堆砌所有条目,再手动加一些 margin 或 padding 来区分。这样做虽然能跑起来,但遇到复杂的分组列表时,视觉上往往一片混沌——用户分不清哪里是一个分组的结束、哪里是下一个分组的开始。
解决方案:合理使用 Divider(分隔线)组件,配合 Column 的纵向排列能力,构建出层次分明、呼吸感十足的列表界面。
本文将以一个完整的「设置页」Demo 为例,手把手带你掌握 Column + Divider 的最佳实践,涵盖分隔线的粗细控制、颜色搭配、缩进策略等实战技巧。
二、前置知识:Column 与 Divider 基础
在深入案例之前,先快速回顾一下这两个组件的核心特性。
2.1 Column:纵向排列容器
Column 是鸿蒙 ArkTS 中三大基础布局容器之一(另外两个是 Row 和 Flex),子组件沿垂直方向从上到下依次排列。
Column({ space: 12 }) { // space 控制子项间距
Text('第一项')
Text('第二项')
Text('第三项')
}
.width('100%')
关键属性:
| 属性 | 类型 | 说明 |
|---|---|---|
space |
number | string | 子组件之间的间距,单位 vp |
alignItems |
HorizontalAlign | 水平对齐方式(Start / Center / End) |
justifyContent |
FlexAlign | 垂直方向主轴对齐方式 |
2.2 Divider:分隔线组件
Divider 是一个轻量的分割线组件,通常用于区分列表项、分组或内容区块。
Divider()
.width('100%') // 线宽
.height(1) // 线粗(垂直方向厚度)
.color('#E8E8E8') // 颜色
.strokeLineCap(LineCapStyle.Round) // 线帽样式
.margin({ left: 16, right: 16 }) // 外边距
关键属性:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
width |
Length | ‘100%’ | 分隔线的宽度 |
height |
Length | 1 | 分隔线的粗细(厚度) |
color |
ResourceColor | ‘#33182431’ | 线条颜色 |
strokeLineCap |
LineCapStyle | Butt | 线帽样式:Butt(平头)、Round(圆头)、Square(方头) |
注意:在 ArkTS 中,
Divider默认是一个水平线,height控制线的粗细。
三、案例实战:仿系统「设置页」
光说不练假把式。我们用一个真实的 Demo——仿 HarmonyOS 系统设置页——来演示 Column + Divider 的组合拳。
3.1 最终效果预览
页面结构如下:
┌─────────────────────────────────┐
│ ⚙️ 设置 v1.0.0 │ ← 顶部标题栏
├─────────────────────────────────┤
│ 个人信息 │ ← 分组标题(小字灰色)
│ 👤 账号与安全 │
│ 密码、指纹、面部识别 │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ ← 细分隔线(0.5px,缩进52vp)
│ 📱 隐私 │
│ 权限管理、广告追踪 │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ 🔒 密码与账户 │
│ 应用密码、自动填充 │
├═════════════════════════════════┤ ← 粗分隔线(8px,与背景同色=留白)
│ 通知与显示 │
│ 🔔 通知管理 │
│ ... │
├═════════════════════════════════┤
│ 其他设置 │
│ ... │
└─────────────────────────────────┘
3.2 完整代码
/**
* Column × Divider 最佳实践
* ──────────────────────────────
* 场景:用 Divider 提升纵向列表的视觉层次
* 核心技术:Divider, Column, 分隔线样式
*
* 布局要点:
* 1. Column 作为纵向排列容器,Divider 作为分隔元素嵌入其中
* 2. Divider 支持多种样式:粗细(height)、颜色(color)、线帽样式(strokeLineCap)
* 3. 合理运用 Divider 的 margin 可增强视觉呼吸感
* 4. 不同粗细/颜色的 Divider 可表达不同的层次关系
* 5. 使用 @Builder 将重复 UI 片段抽离为构建函数
*/
@Entry
@Component
struct DividerColumnDemo {
// ─── 模拟的列表数据 ───
@State private sections: SectionItem[] = [
{
title: '个人信息',
items: [
{ icon: '\u{1F464}', label: '账号与安全', desc: '密码、指纹、面部识别' },
{ icon: '\u{1F4F1}', label: '隐私', desc: '权限管理、广告追踪' },
{ icon: '\u{1F512}', label: '密码与账户', desc: '应用密码、自动填充' }
]
},
{
title: '通知与显示',
items: [
{ icon: '\u{1F514}', label: '通知管理', desc: '应用通知、锁屏通知' },
{ icon: '\u{1F4FA}', label: '显示与亮度', desc: '深色模式、字体大小' },
{ icon: '\u{1F30D}', label: '壁纸与个性化', desc: '壁纸、主题、图标' }
]
},
{
title: '其他设置',
items: [
{ icon: '\u{1F4E6}', label: '应用管理', desc: '应用列表、默认应用' },
{ icon: '\u{26A1}', label: '电池', desc: '省电模式、耗电排行' },
{ icon: '\u{1F527}', label: '系统更新', desc: '检查更新、自动更新' }
]
}
];
// ─── 构建页面入口 ───
build() {
Column() {
// 顶部标题栏(直接使用 @Builder)
this.buildTitleBar();
// 可滚动的列表主体
Scroll() {
Column() {
// 遍历每个分组
ForEach(this.sections, (section: SectionItem, index: number) => {
// 分组间插入粗分隔线(第一个分组前不显示)
if (index > 0) {
this.buildSectionDivider();
}
// 分组标题
this.buildSectionTitle(section.title);
// 分组内列表项
ForEach(section.items, (item: ListItemData, itemIndex: number) => {
this.buildListItem(item, itemIndex, section.items.length);
})
})
}
.width('100%')
.padding({ left: 16, right: 16, top: 12, bottom: 24 })
}
.scrollBar(BarState.Off) // 隐藏滚动条,保持界面清爽
.edgeEffect(EdgeEffect.Spring) // 边缘回弹效果
.width('100%')
.layoutWeight(1) // 填充剩余空间
}
.width('100%')
.height('100%')
.backgroundColor('#F2F3F5') // 浅灰背景,衬托卡片区域
}
// ════════════════════════════════════
// @Builder:可复用的 UI 片段
// ════════════════════════════════════
@Builder
buildTitleBar() {
Column() {
Row() {
Text('\u{2699}\u{FE0F}')
.fontSize(22)
Text('设置')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ left: 8 })
Blank()
Text('v1.0.0')
.fontSize(13)
.fontColor('#999')
}
.width('100%')
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
}
.width('100%')
.backgroundColor('#FFFFFF')
}
@Builder
buildSectionDivider() {
Column() {
Divider()
.width('100%')
.height(8)
.color('#F2F3F5')
.margin({ top: 8, bottom: 4 })
}
.width('100%')
}
@Builder
buildSectionTitle(title: string) {
Text(title)
.fontSize(13)
.fontColor('#666666')
.fontWeight(FontWeight.Medium)
.margin({ top: 4, bottom: 8, left: 4 })
.width('100%')
}
@Builder
buildListItem(item: ListItemData, itemIndex: number, totalCount: number) {
Column() {
Row() {
Text(item.icon)
.fontSize(22)
.width(36)
.height(36)
.textAlign(TextAlign.Center)
.lineHeight(36)
Column() {
Text(item.label)
.fontSize(16)
.fontColor('#1A1A1A')
.fontWeight(FontWeight.Medium)
Text(item.desc)
.fontSize(12)
.fontColor('#999999')
}
.margin({ left: 12 })
.layoutWeight(1)
Text('>')
.fontSize(16)
.fontColor('#CCCCCC')
}
.width('100%')
.padding({ top: 14, bottom: 14, left: 12, right: 12 })
.alignItems(VerticalAlign.Center)
if (itemIndex < totalCount - 1) {
Divider()
.width('100%')
.height(0.5)
.color('#E8E8E8')
.margin({ left: 52 })
}
}
.width('100%')
.backgroundColor('#FFFFFF')
}
}
interface ListItemData {
icon: string;
label: string;
desc: string;
}
interface SectionItem {
title: string;
items: ListItemData[];
}
四、逐层解析:Column + Divider 的设计密码
4.1 第一层:全局 Column + Scroll
Column() {
this.buildTitleBar();
Scroll() {
Column() { /* 列表内容 */ }
}
.layoutWeight(1)
}
整个页面是一个大的 Column,包含标题栏和可滚动列表。关键点:
layoutWeight(1):让Scroll自动填充标题栏下方的所有剩余空间,无需手动计算高度。Scroll+Column:内层Column负责纵向排列所有分组和列表项,外层Scroll提供内容溢出时的滚动能力。edgeEffect(EdgeEffect.Spring):滚动到边缘时有弹性回弹效果,提升交互质感。
4.2 第二层:双轨 Divider 体系
这是本文最核心的设计模式——建立「粗细两档」分隔线体系:
粗分隔线(分组级):height(8), color('#F2F3F5')
Divider()
.width('100%')
.height(8)
.color('#F2F3F5')
作用:表示「章节切换」。颜色与页面背景色 #F2F3F5 相同,所以视觉上看起来不是一个「线」,而是一段留白间隔——这比直接用 margin 更优雅,因为 Divider 占据了布局中的独立位置,不会受相邻元素 margin 折叠的影响。
细分隔线(列表项级):height(0.5), color('#E8E8E8'), margin({left: 52})
Divider()
.width('100%')
.height(0.5)
.color('#E8E8E8')
.margin({ left: 52 })
作用:表示「同组内相邻项」。这里的精妙之处在于:
- 0.5px 极细:视觉上若有若无,不会抢夺内容的注意力。
- 缩进 52vp:从图标右侧开始对齐,避免分隔线「贯穿」左侧图标区域,视觉上更干净。
- 最后一项不画:通过
if (itemIndex < totalCount - 1)条件控制,末尾无分隔线,让卡片底部留有完整白边。
双轨对比
| 维度 | 粗分隔线 | 细分隔线 |
|---|---|---|
| height | 8vp | 0.5vp |
| color | #F2F3F5(背景同色) | #E8E8E8(浅灰) |
| 作用 | 分组之间的大间隔 | 列表项之间的微分割 |
| 视觉效果 | 留白区块 | 若有若无的细线 |
| 缩进 | 无(全宽) | left: 52vp |
4.3 第三层:@Builder 抽离 UI 结构
在 ArkTS 中,build() 方法内只能使用声明式 UI 语法。如果像传统面向对象编程那样定义普通成员方法并在 build() 中调用,编译器会报错:
'this.buildTitleBar();' does not meet UI component syntax.
正确的做法是使用 @Builder 装饰器:
@Builder
buildListItem(item: ListItemData, itemIndex: number, totalCount: number) {
// 这里可以写 Column, Row, Text, Divider 等任何 UI 组件
}
@Builder 的优点:
- 复用性:相同结构的 UI 片段只需定义一次
- 参数化:可以接收外部传入的数据和状态
- 可嵌套:
@Builder内部可以调用另一个@Builder - 类型安全:参数有明确的类型定义,IDE 可自动补全
4.4 第四层:数据驱动渲染
我们用了两组 ForEach:
// 外层:遍历分组
ForEach(this.sections, (section: SectionItem, index: number) => { ... })
// 内层:遍历某分组内的所有列表项
ForEach(section.items, (item: ListItemData, itemIndex: number) => { ... })
这种「双层 ForEach」模式非常适用于分组列表场景。如果将来需要增删改列表项,只需修改 @State 装饰的 sections 数组,UI 会自动响应更新。
五、进阶技巧与避坑指南
5.1 分隔线颜色使用语义化色板
不要随手写一个颜色值。推荐为分隔线建立语义化色板:
| token | 值 | 用途 |
|---|---|---|
--divider-strong |
#E8E8E8 |
列表项分隔线 |
--divider-section |
#F2F3F5 |
分组间隔(与背景同色) |
--divider-card-border |
#DCDCDC |
卡片描边 |
5.2 Divider 的 strokeLineCap 妙用
当分隔线较短(非全宽)时,strokeLineCap 可以改变线条端点的形状:
Divider()
.width(80) // 固定宽度而非 100%
.height(2)
.strokeLineCap(LineCapStyle.Round) // 圆头端点
.color('#007AFF')
效果:一条两端圆润的短蓝线,常用于「查看更多」之类的装饰性分割。
5.3 避免 margin 折叠陷阱
在 CSS 中,相邻元素的 margin 会折叠(取最大值)。但在 ArkTS 中,Column 的子组件之间的 margin 不会折叠。不过用 Divider 代替 margin 来制造间隔有一个额外好处——Divider 是独立组件,可以单独设置 hitTestBehavior,不会意外拦截点击事件。
5.4 与 List 组件的权衡
ArkTS 提供了专门的 List + ListItem 组件用于长列表。那为什么不直接用 List?
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 简单的同构列表 | List + ListItem |
懒加载、回收机制,性能更好 |
| 复杂的分组布局 | Scroll + Column + Divider |
布局更灵活,可嵌入任意嵌套结构 |
| 卡片式列表 | Scroll + Column |
每个卡片可以独立设置背景、圆角、阴影 |
本案例采用 Scroll + Column 就是因为分组标题 + 列表项 + 分隔线的异构结构在 Column 中表达更自然。
5.5 Divider 与空白占位的搭配
除了分隔线本身,Divider 还可以配合空白组件实现更丰富的视觉效果:
Row() {
Divider().height(1).color('#E0E0E0').layoutWeight(1)
Text(' OR ').fontSize(12).fontColor('#999')
Divider().height(1).color('#E0E0E0').layoutWeight(1)
}
这是登录页常见的「OR 分割线」实现方式。
六、性能要点
对于本案例(3 组 × 3 项 = 9 个列表项),Scroll + Column 模式的性能完全足够。但如果列表规模增长到几百项,建议关注以下优化点:
- ForEach 的 keyGenerator:给每个列表项提供唯一的
key,帮助框架精准复用组件。 - 避免 @Builder 内的冗余重建:如果
@Builder的参数是复杂对象,确保数据不可变以触发最小更新。 - LazyForEach 替代 ForEach:数据量超过 50 项时,改用
LazyForEach实现懒加载。
// 大数据量时使用 LazyForEach
LazyForEach(this.dataSource, (item: DataItem, index: number) => {
ListItem() { /* ... */ }
}, (item: DataItem) => item.key)
七、扩展:给列表加上「卡片化」样式
如果觉得现在的全宽列表略显单调,可以轻松升级为卡片式设计——只需要在外层 Column 添加背景色和圆角:
@Builder
buildCardGroup(section: SectionItem) {
Column() {
this.buildSectionTitle(section.title);
ForEach(section.items, (item: ListItemData, itemIndex: number) => {
this.buildListItem(item, itemIndex, section.items.length);
})
}
.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius(12) // 圆角
.shadow({ // 阴影
radius: 4,
color: 'rgba(0,0,0,0.06)',
offsetX: 0,
offsetY: 2
})
.padding(0)
}
然后分组之间的粗分隔线保留不变,这样就变成了一张张「卡片」堆叠的效果——视觉上更接近 iOS 的设置页风格。
八、写在最后
通过本文的完整案例,我们深入探索了鸿蒙 ArkTS 中 Column 与 Divider 的搭配技巧。总结核心要点:
- 粗细分级:建立粗(分组级)与细(项级)两档分隔线,让视觉层次一目了然。
- 颜色即留白:分隔线颜色与背景色相同,就能制造出「无形的间距块」。
- 缩进对齐:列表项分隔线从图标右侧开始,避免贯穿图标区域。
- @Builder 抽离:将重复的 UI 片段封装为
@Builder方法,保持代码整洁。 - Scroll + Column 组合:灵活应对异构分组列表,比
List组件更可控。
分隔线虽小,却是界面设计中不可或缺的「视觉标点符号」。用好 Column 与 Divider 的组合,你的鸿蒙应用列表页面将从此告别「一团和气」的平庸感,呈现专业级的视觉层次。
最后,建议你打开 DevEco Studio,创建一个新的 ArkTS 项目,把本文的 Demo 代码贴进去运行看看——眼见为实,亲手调试一次比读十遍文章更有收获。
本文配套代码已通过 HarmonyOS NEXT API 24 编译验证,可在 DevEco Studio 5.0+ 中直接运行。


更多推荐


所有评论(0)