鸿蒙原生 ArkTS 布局方式深度解析:Column + alignItems(Start) 垂直排列
这里写自定义目录标题
- 鸿蒙原生 ArkTS 布局方式深度解析:Column + alignItems(Start) 垂直排列
- 欢迎使用Markdown编辑器
鸿蒙原生 ArkTS 布局方式深度解析:Column + alignItems(Start) 垂直排列

SDK 版本:HarmonyOS NEXT 6.1.1(API 24)
开发语言:ArkTS(声明式 UI)
项目模式:Stage 模型
适用场景:纵向列表、表单、信息流页面、个人资料页
目录
- 开篇:HarmonyOS NEXT 与 ArkTS 声明式 UI
- 项目结构概览
- Column 容器布局原理
- ColumnStart 布局详解(核心)
- alignItems 三种取值效果对比
- justifyContent 垂直对齐控制
- 实战场景一:信息流列表
- 实战场景二:表单页面
- 实战场景三:番茄钟应用
- @Builder 装饰器:复用布局组件
- 路由与页面导航
- 布局要点总结
- 常见问题与调试技巧
- 结语
1. 开篇:HarmonyOS NEXT 与 ArkTS 声明式 UI
HarmonyOS NEXT 是华为推出的全栈自研操作系统,从内核到应用框架完全去除了 Android 代码,采用自研的鸿蒙内核。HarmonyOS NEXT 6.1.1(API 24)是当前最新的稳定版本,为开发者提供了完善的 ArkTS 声明式 UI 开发体系。
ArkTS(Ark TypeScript)是鸿蒙原生应用开发语言,基于 TypeScript 语法扩展,加入了响应式状态管理、装饰器、声明式 UI 等特性。它与 SwiftUI(iOS)、Jetpack Compose(Android)的理念类似,但在布局系统上有着自己独特的设计。
在 ArkTS 中,布局的核心思想是 「容器 + 子组件 + 对齐方式」。开发者通过组合不同的容器组件(Column、Row、Flex、Stack、Grid 等)和对齐属性,可以构建任意复杂的 UI 界面。
本文将重点讲解 Column 容器 + alignItems(ItemAlign.Start) + justifyContent(FlexAlign.Start) 这一经典组合,即 ColumnStart 垂直排列布局,并通过完整的可运行代码示例,帮助读者深入理解其原理与应用。
2. 项目结构概览
在开始深入布局细节之前,我们先来看看整个项目的文件结构:
MyApplication4/
├── AppScope/
│ └── app.json5 # 应用全局配置
├── entry/
│ ├── build-profile.json5 # 模块构建配置
│ ├── hvigorfile.ts # 构建脚本
│ ├── oh-package.json5 # 依赖管理
│ └── src/main/
│ ├── ets/
│ │ ├── entryability/
│ │ │ └── EntryAbility.ets # Ability 生命周期管理
│ │ ├── entrybackupability/
│ │ │ └── EntryBackupAbility.ets
│ │ └── pages/
│ │ ├── Index.ets # 首页 - 番茄钟
│ │ └── ColumnStartDemo.ets # 布局演示页
│ └── resources/
│ ├── base/
│ │ ├── element/ # 颜色、字重等资源
│ │ ├── media/ # 图片资源
│ │ └── profile/
│ │ └── main_pages.json # 页面路由注册
│ └── dark/
│ └── element/color.json # 深色模式颜色
├── build-profile.json5 # 工程级构建配置
└── hvigorfile.ts
2.1 页面路由注册
每个页面必须在 main_pages.json 中注册才能被 router.pushUrl() 跳转访问:
{
"src": [
"pages/Index",
"pages/ColumnStartDemo"
]
}
2.2 SDK 版本配置
在根目录的 build-profile.json5 中指定了目标 SDK 版本:
{
"app": {
"products": [
{
"name": "default",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
}
]
}
}
这意味着我们的应用只能在 HarmonyOS NEXT 6.1.1 及以上版本运行,可以充分利用 API 24 提供的新特性。
3. Column 容器布局原理
3.1 Column 是什么
Column 是 ArkTS 中最基础的垂直布局容器。它的工作方式类似于 CSS Flexbox 中的 flex-direction: column——所有子组件沿着垂直方向依次排列。
┌─────────────────────┐
│ ┌─────────────────┐│
│ │ 子组件 1 ││ ← 顶部
│ └─────────────────┘│
│ ┌─────────────────┐│
│ │ 子组件 2 ││
│ └─────────────────┘│
│ ┌─────────────────┐│
│ │ 子组件 3 ││ ← 底部
│ └─────────────────┘│
└─────────────────────┘
3.2 Column 的核心属性
Column 容器主要提供两个布局控制维度:
| 属性 | 作用维度 | 可选值 | 说明 |
|---|---|---|---|
alignItems |
水平方向(X轴) | ItemAlign.Start / Center / End / Stretch / Baseline |
控制子组件在水平方向的对齐方式 |
justifyContent |
垂直方向(Y轴) | FlexAlign.Start / Center / End / SpaceBetween / SpaceAround / SpaceEvenly |
控制子组件在垂直方向的排列方式 |
3.3 类比 CSS Flexbox
对于有 Web 开发经验的读者,理解 Column 的布局体系会更轻松:
| ArkTS | CSS Flexbox 等价 |
|---|---|
Column |
display: flex; flex-direction: column |
Column { Row() } |
flex-direction: column 内嵌 flex-direction: row |
alignItems(ItemAlign.Start) |
align-items: flex-start |
alignItems(ItemAlign.Center) |
align-items: center |
alignItems(ItemAlign.End) |
align-items: flex-end |
justifyContent(FlexAlign.Start) |
justify-content: flex-start |
justifyContent(FlexAlign.SpaceBetween) |
justify-content: space-between |
.width('100%') |
width: 100% |
.padding() |
padding |
.margin() |
margin |
4. ColumnStart 布局详解(核心)
4.1 定义
所谓 ColumnStart 布局,指的是:
Column() {
// 子组件列表...
}
.width('100%')
.alignItems(ItemAlign.Start) // ← 水平方向左对齐
.justifyContent(FlexAlign.Start) // ← 垂直方向顶部对齐
4.2 布局效果
- 水平方向:所有子组件的左侧边缘对齐到容器的左侧
- 垂直方向:子组件从容器的顶部开始依次排列
视觉效果:
┌──────────────────────────────────┐
│子组件 1(宽度自适应) │ ← 顶部开始
│子组件 2(宽度自适应) │
│子组件 3(宽度自适应) │
│ │ ← 底部留空
└──────────────────────────────────┘
4.3 完整的最小示例
最简单最纯粹的 ColumnStart 布局只需要几行代码:
@Entry
@Component
struct SimpleColumnStart {
build() {
Column() {
Text('标题')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('这是一段描述文字,用于说明布局效果。')
.fontSize(14)
.lineHeight(22)
Button('确认')
.width(120)
.height(40)
}
.width('100%')
.height('100%')
.alignItems(ItemAlign.Start) // 水平左对齐
.justifyContent(FlexAlign.Start) // 垂直顶部对齐
.padding(20)
}
}
运行效果:三个组件(Text → Text → Button)全部靠左上角排列,从上往下依次显示。
4.4 为什么 ColumnStart 如此重要
在移动应用中,绝大多数页面布局都属于 「从上往下读」 的模式:
- 列表页:标题在顶部,列表项依次往下排列
- 详情页:标题、作者、正文、标签从上到下
- 表单页:标签 + 输入框成对出现,从上到下排列
- 个人中心:头像、昵称、统计数据、功能菜单依次排列
ColumnStart 正好满足这种自然的阅读顺序,因此它是 ArkTS 开发中最常用、最基础的布局模式。
5. alignItems 三种取值效果对比
理解 alignItems 的不同取值,是掌握 Column 布局的关键。我们在 ColumnStartDemo.ets 中专门构建了一个对比区块,使用三个等大的彩色方块(A、B、C)来直观展示差异。
5.1 ItemAlign.Start(左对齐)
Column() {
this.buildDemoBlock('A', '#FF6B6B') // 红色方块
this.buildDemoBlock('B', '#4ECDC4') // 青色方块
this.buildDemoBlock('C', '#45B7D1') // 蓝色方块
}
.width('100%')
.alignItems(ItemAlign.Start) // ← 左对齐
效果:
┌──────────────────────────────────────┐
│[A████████] │ ← 全部靠左
│[B████████] │
│[C████████] │
└──────────────────────────────────────┘
所有子组件的左边缘对齐到容器左边缘。由于方块宽度固定(80vp),它们整齐地排列在左侧。
5.2 ItemAlign.Center(居中对齐)
Column() {
this.buildDemoBlock('A', '#FF6B6B')
this.buildDemoBlock('B', '#4ECDC4')
this.buildDemoBlock('C', '#45B7D1')
}
.width('100%')
.alignItems(ItemAlign.Center) // ← 居中对齐
效果:
┌──────────────────────────────────────┐
│ [A████████] │ ← 全部居中
│ [B████████] │
│ [C████████] │
└──────────────────────────────────────┘
所有子组件的中心线对齐到容器中心。对于宽度不一致的子组件,它们会以中线为准对齐,左右边距不对称。
5.3 ItemAlign.End(右对齐)
Column() {
this.buildDemoBlock('A', '#FF6B6B')
this.buildDemoBlock('B', '#4ECDC4')
this.buildDemoBlock('C', '#45B7D1')
}
.width('100%')
.alignItems(ItemAlign.End) // ← 右对齐
效果:
┌──────────────────────────────────────┐
│ [A████████]│ ← 全部靠右
│ [B████████]│
│ [C████████]│
└──────────────────────────────────────┘
所有子组件的右边缘对齐到容器右边缘。这种布局在常规页面中较少使用,但适用于特定的设计需求(如右上角的操作菜单)。
5.4 对比总结
| 取值 | 对齐基准 | 适用场景 |
|---|---|---|
ItemAlign.Start |
左边缘 | 信息流列表、表单、文章详情、设置页 |
ItemAlign.Center |
中心线 | 弹窗、提示卡片、加载动画 |
ItemAlign.End |
右边缘 | 右上角操作菜单、特殊对齐需求 |
5.5 关于 ItemAlign.Stretch
还有一个常用值 ItemAlign.Stretch,它会让子组件在水平方向拉伸填满容器宽度,相当于子组件的 width 变为 100%(如果子组件未设置固定宽度)。这在表单布局中非常有用:
Column() {
TextInput({ placeholder: '输入框1' })
TextInput({ placeholder: '输入框2' })
Button('提交')
}
.width('100%')
.alignItems(ItemAlign.Stretch) // 所有子组件拉伸填满
6. justifyContent 垂直对齐控制
justifyContent 控制子组件在垂直方向(Column 的主轴方向)的排列方式。
6.1 FlexAlign.Start(顶部对齐)
Column() {
Text('顶部对齐')
Text('内容紧贴顶部')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
效果:子组件从容器顶部开始排列,底部留空。
6.2 FlexAlign.Center(垂直居中)
Column() {
Text('居中显示')
Text('内容在正中间')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
效果:子组件的整体在容器垂直中央。
6.3 FlexAlign.End(底部对齐)
Column() {
Text('底部对齐')
Text('内容紧贴底部')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.End)
效果:子组件排列在容器底部。
6.4 FlexAlign.SpaceBetween(两端对齐)
Column() {
Text('顶部')
Text('中间')
Text('底部')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.SpaceBetween)
效果:第一个子组件在顶部,最后一个在底部,剩余空间均匀分配给元素之间的间隙。
6.5 FlexAlign.SpaceEvenly(均匀分布)
Column()
.justifyContent(FlexAlign.SpaceEvenly)
效果:所有间隙(包括顶部和底部边缘到第一个/最后一个元素的距离)完全相等。
6.6 实际应用建议
在 ColumnStart 布局中,我们使用 FlexAlign.Start 作为默认值,因为大多数页面都是从顶部开始阅读的。但某些场景下可以灵活变化:
- 个人中心页顶部:
FlexAlign.Start,信息从上往下排列 - 对话弹窗:
FlexAlign.Center,内容居中显示 - 底部操作栏:
FlexAlign.End,按钮固定在底部
7. 实战场景一:信息流列表
信息流列表是 ColumnStart 最经典的应用场景。在 ColumnStartDemo.ets 中,我们构建了 5 条模拟信息流数据,每条卡片内部也采用 ColumnStart 布局。
7.1 数据模型
首先定义数据结构:
interface FeedItem {
id: number;
title: string;
summary: string;
tag: string;
time: string;
icon: string;
}
7.2 状态数据
使用 @State 装饰器声明响应式数据:
@State feedList: FeedItem[] = [
{
id: 1,
title: 'HarmonyOS NEXT 正式发布',
summary: '全新鸿蒙内核,不再兼容 Android 应用,全栈自研操作系统面向万物互联。',
tag: '资讯',
time: '10 分钟前',
icon: '🚀'
},
{
id: 2,
title: 'ArkTS 声明式 UI 最佳实践',
summary: '学习如何使用 @State、@Prop、@Link 装饰器管理组件状态。',
tag: '教程',
time: '1 小时前',
icon: '📘'
},
// ... 更多数据
];
7.3 卡片布局(双重复合 ColumnStart)
每张信息流卡片内部也采用 ColumnStart 布局,形成 「外层 Column 列表 → 内层 Column 卡片」 的双层结构:
@Builder
buildFeedCard(item: FeedItem): void {
Column() {
// ─ 第一行:图标 + 标题 ─
Row() {
Text(item.icon)
.fontSize(24)
.margin({ right: 10 })
Text(item.title)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#2C3E50')
}
.margin({ bottom: 6 })
// ─ 摘要(左对齐,自动换行) ─
Text(item.summary)
.fontSize(13)
.fontColor('#636E72')
.lineHeight(20)
.margin({ bottom: 10 })
// ─ 标签 + 时间 ─
Row() {
Text(item.tag)
.fontSize(11)
.fontColor('#FFFFFF')
.backgroundColor('#4ECDC4')
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
.borderRadius(10)
Text('·')
.fontSize(11)
.fontColor('#BDC3C7')
.margin({ left: 8, right: 8 })
Text(item.time)
.fontSize(11)
.fontColor('#BDC3C7')
}
}
.width('100%')
.alignItems(ItemAlign.Start) // ← 卡片内左对齐
.padding(14)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.border({ width: 1, color: '#EEEEEE' })
.margin({ bottom: 10 })
.onClick(() => {
this.onCardTap(item);
})
}
7.4 列表渲染
使用 ForEach 循环渲染:
ForEach(this.feedList, (item: FeedItem) => {
this.buildFeedCard(item)
}, (item: FeedItem) => item.id.toString())
7.5 布局分析
每张卡片内部的布局结构:
┌──────────────────────────────────────┐
│🚀 HarmonyOS NEXT 正式发布 │ ← Row (图标 + 标题)
│全新鸿蒙内核,不再兼容 Android 应用... │ ← Text (摘要,多行)
│[资讯] · 10 分钟前 │ ← Row (标签 + 时间)
└──────────────────────────────────────┘
所有内容的左边缘都在一条垂直线上,形成了清晰的视觉引导。这就是 ColumnStart 的威力——不需要复杂的嵌套对齐设置,所有子组件自然左对齐。
8. 实战场景二:表单页面
表单是 ColumnStart 的另一大典型场景。标签和输入框的「上下结构」天生适合 Column 布局。
8.1 表单容器
Column() {
// ── 标签 ──
Text('姓名')
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#2C3E50')
.margin({ bottom: 6 })
// ── 输入框 ──
TextInput({ placeholder: '请输入您的姓名', text: this.userName })
.width('100%')
.height(44)
.padding({ left: 12 })
.backgroundColor('#F8F9FA')
.borderRadius(8)
.onChange((val: string) => { this.userName = val; })
.margin({ bottom: 16 })
// ── 邮箱 ──
Text('电子邮箱')
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#2C3E50')
.margin({ bottom: 6 })
TextInput({ placeholder: '请输入邮箱地址', text: this.userEmail })
.width('100%')
.height(44)
.padding({ left: 12 })
.backgroundColor('#F8F9FA')
.borderRadius(8)
.onChange((val: string) => { this.userEmail = val; })
.margin({ bottom: 16 })
// ── 提交按钮 ──
Button('提交信息')
.width('100%')
.height(48)
.backgroundColor('#4ECDC4')
.fontColor('#FFFFFF')
.fontSize(16)
.borderRadius(24)
.onClick(() => { this.onSubmitForm(); })
}
.width('100%')
.padding(16)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.border({ width: 1, color: '#E8E8E8' })
8.2 布局分析
┌──────────────────────────────────────┐
│姓名 │ ← 标签顶部对齐
│[┌────────────────────────────────┐] │ ↓
│[│ 请输入您的姓名 │] │ 输入框
│[└────────────────────────────────┘] │ ↓
│电子邮箱 │
│[┌────────────────────────────────┐] │
│[│ 请输入邮箱地址 │] │
│[└────────────────────────────────┘] │
│手机号(选填) │
│[┌────────────────────────────────┐] │
│[│ 请输入手机号 │] │
│[└────────────────────────────────┘] │
│ │
│[┌════════════════════════════════┐] │
│[║ 提交信息 ║] │ ← 按钮宽度 100%
│[└════════════════════════════════┘] │
└──────────────────────────────────────┘
8.3 关键设计要点
- 标签在上,输入框在下:每个表单项是一个「标签 + 输入框」的垂直组合
- 标签左对齐:Text 组件默认左对齐,与 ColumnStart 一致
- 输入框宽度 100%:通过
.width('100%')撑满容器,确保表单整齐 - 输入框类型:手机号输入框使用
.type(InputType.PhoneNumber)调用数字键盘 - 圆角设计:使用
.borderRadius()营造现代 UI 风格
8.4 表单验证
private onSubmitForm(): void {
if (!this.userName.trim() || !this.userEmail.trim()) {
promptAction.showToast({
message: '请填写姓名和邮箱',
duration: 1500
});
return;
}
promptAction.showToast({
message: `已提交 ${this.userName} 的表单`,
duration: 2000
});
}
9. 实战场景三:番茄钟应用
Index.ets 是一个完整的番茄钟(Pomodoro Timer)应用,虽然它的主布局使用的是 alignItems(HorizontalAlign.Center)(居中对齐),而不是 Start,但它的整体结构仍然是 Column 垂直布局。这个例子展示了 Column 布局在实际应用中的灵活运用。
9.1 布局结构
build() {
Column() {
// ① 顶部标题
Text('🍅 番茄钟')
// ② 阶段标签("专注工作" / "休息时间")
Text(this.phaseText)
// ③ 计时器圆环(Canvas 绘制)
Stack() { Canvas(this.ctx) }
// ④ 控制按钮(Row 水平布局)
Row() { Button('▶ 开始'); Button('↻ 重置') }
// ⑤ 已完成番茄数
Row() { /* 番茄图标列表 */ }
Text(`已完成 ${this.completedSessions} 个番茄`)
// ⑥ 提示文字
Text('专注 25 分钟,休息 5 分钟')
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Center) // ← 这里用了 Center
}
9.2 为什么番茄钟使用 Center 而不是 Start
番茄钟是一个 「焦点型」 应用——用户盯着计时器看,所有 UI 元素围绕计时器在视觉中心布局。因此采用居中布局更合理:
┌──────────────────────┐
│ 🍅 番茄钟 │
│ 专注工作 │
│ │
│ ┌───────────┐ │
│ │ 25:00 │ │ ← 计时器居中
│ │ ● 进行中 │ │
│ └───────────┘ │
│ │
│ [▶ 开始] [↻ 重置] │
│ 🍅 ○ ○ ○ │
└──────────────────────┘
这正好说明:没有绝对的"最佳布局",只有最适合场景的布局。
9.3 Canvas 绘制计时圆环
番茄钟的核心是使用 Canvas 组件绘制的环形进度条:
private drawRing(): void {
const ctx = this.ctx;
const cx = this.CX; // 圆心 X: 120
const cy = this.CY; // 圆心 Y: 120
const r = this.RING_RADIUS; // 半径: 100
const lw = this.RING_WIDTH; // 线宽: 10
// ① 清空画布
ctx.clearRect(0, 0, this.RING_SIZE, this.RING_SIZE);
// ② 绘制背景圆环(浅色)
ctx.beginPath();
ctx.arc(cx, cy, r, 0, Math.PI * 2);
ctx.strokeStyle = this.secondaryColor; // #FFE0E0 或 #D4F5F2
ctx.lineWidth = lw;
ctx.stroke();
// ③ 绘制进度弧(主色)
if (this.progress > 0) {
const startAngle = -Math.PI / 2; // 从12点钟方向开始
const sweepAngle = Math.PI * 2 * this.progress;
const endAngle = startAngle + sweepAngle;
ctx.beginPath();
ctx.arc(cx, cy, r, startAngle, endAngle);
ctx.strokeStyle = this.primaryColor; // #FF6B6B 或 #4ECDC4
ctx.lineWidth = lw;
ctx.lineCap = 'round'; // 圆角端点
ctx.stroke();
}
// ④ 绘制中央时间文字
ctx.font = '48px sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#2D3436';
ctx.fillText(this.timeDisplay, cx, cy - 8);
// ⑤ 绘制状态文字
ctx.font = '14px sans-serif';
ctx.fillStyle = '#636E72';
if (this.showFinishTip) {
ctx.fillText('⏰ 时间到!', cx, cy + 32);
} else if (this.isRunning) {
ctx.fillText('● 进行中', cx, cy + 32);
} else if (this.remainingTime < this.totalTime) {
ctx.fillText('⏸ 已暂停', cx, cy + 32);
}
}
9.4 状态管理
番茄钟使用多个 @State 装饰器管理的响应式状态变量:
@State remainingTime: number = 25 * 60; // 剩余时间(秒)
@State isRunning: boolean = false; // 是否运行中
@State isWorkPhase: boolean = true; // 工作/休息阶段
@State completedSessions: number = 0; // 已完成番茄数
@State phaseText: string = '专注工作'; // 阶段文字
@State showFinishTip: boolean = false; // 是否显示完成提示
9.5 定时器逻辑
使用 setInterval 实现每秒倒计时:
private startTimer(): void {
if (this.isRunning) return;
this.isRunning = true;
this.showFinishTip = false;
this.timerId = setInterval(() => {
let next = this.remainingTime - 1;
if (next <= 0) {
this.remainingTime = 0;
this.isRunning = false;
this.clearTimer();
this.onPhaseComplete();
} else {
this.remainingTime = next;
}
this.drawRing(); // 每秒钟重绘一次圆环
}, 1000);
}
9.6 阶段切换
private onPhaseComplete(): void {
this.showFinishTip = true;
if (this.isWorkPhase) {
// 工作完成 → 进入休息
this.completedSessions++;
this.isWorkPhase = false;
this.phaseText = '休息时间';
this.remainingTime = this.BREAK_TIME; // 5分钟
} else {
// 休息完成 → 进入工作
this.isWorkPhase = true;
this.phaseText = '专注工作';
this.remainingTime = this.WORK_TIME; // 25分钟
}
this.drawRing();
}
10. @Builder 装饰器:复用布局组件
在 ColumnStartDemo.ets 中,我们大量使用了 @Builder 装饰器来创建可复用的布局组件。这是 ArkTS 提升代码复用性的重要特性。
10.1 @Builder 基础用法
@Builder 用于定义非 build() 方法内的 UI 构建函数,可以在 build() 方法中多次调用:
@Builder
buildDemoBlock(label: string, color: string): void {
Text(label)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
.width(80)
.height(44)
.textAlign(TextAlign.Center)
.backgroundColor(color)
.borderRadius(6)
.margin({ bottom: 6 })
}
然后在 build() 中调用:
Column() {
this.buildDemoBlock('A', '#FF6B6B')
this.buildDemoBlock('B', '#4ECDC4')
this.buildDemoBlock('C', '#45B7D1')
}
10.2 @Builder 的三个优势
- 去重:同样的卡片或区块不需要重复写相同的代码
- 参数化:通过函数参数控制颜色、文字、数据等,灵活适应不同场景
- 作用域内:@Builder 方法可以访问 struct 的所有成员变量和 @State 状态
10.3 本项目中定义的 @Builder 方法
| 方法名 | 用途 | 参数 |
|---|---|---|
buildDemoBlock |
构建对比演示方块 | label: string, color: string |
buildFeedCard |
构建信息流卡片 | item: FeedItem |
buildTipRow |
构建布局要点提示行 | text: string |
10.4 @Builder 与 @Component 的选择
| 特性 | @Builder | @Component |
|---|---|---|
| 独立 struct | 否,定义在父组件内 | 是,独立的 struct |
| 访问父组件状态 | 可直接访问 | 需通过 @Prop/@Link 传入 |
| 复用范围 | 当前 struct 内 | 全局复用 |
| 性能 | 轻量,无创建开销 | 有组件实例化开销 |
| 适用场景 | 页面内的局部复用 | 跨页面复用的独立组件 |
11. 路由与页面导航
11.1 导入路由模块
import router from '@ohos.router';
11.2 跳转到新页面
Button('📐 查看 ColumnStart 布局演示')
.onClick(() => {
router.pushUrl({ url: 'pages/ColumnStartDemo' });
})
11.3 返回上一页
private goBack(): void {
router.back();
}
11.4 路由栈机制
router.pushUrl() 将新页面压入路由栈,保留当前页面。用户可以通过 router.back() 逐级返回。这种机制非常适合:
- 主页面 → 详情页:主页面保留在栈中,返回时不丢失状态
- 列表页 → 详情页:从详情页返回列表页时,列表可以保持滚动位置
11.5 页面生命周期
当使用路由导航时,页面的生命周期回调会被触发:
Index(首页)
│
├── aboutToAppear() ← 首页创建
│
├── router.pushUrl() ← 跳转到 ColumnStartDemo
│
│ ColumnStartDemo
│ ├── aboutToAppear()
│ └── (用户操作)
│
├── router.back() ← 返回首页
│
└── ColumnStartDemo.aboutToDisappear()
12. 布局要点总结
12.1 ColumnStart 核心配置
Column() {
// 子组件列表...
}
.width('100%')
.alignItems(ItemAlign.Start) // 水平左对齐
.justifyContent(FlexAlign.Start) // 垂直顶部对齐
12.2 代码对比速查
| 布局名称 | alignItems | justifyContent | 效果 |
|---|---|---|---|
| ColumnStart | ItemAlign.Start |
FlexAlign.Start |
左上对齐 |
| ColumnCenter | ItemAlign.Center |
FlexAlign.Start |
居中对齐 |
| ColumnEnd | ItemAlign.End |
FlexAlign.Start |
右上对齐 |
| 居中布局 | ItemAlign.Center |
FlexAlign.Center |
正中央 |
| 底部居左 | ItemAlign.Start |
FlexAlign.End |
左下角 |
12.3 常用属性速查
Column()
.width('100%') // 宽度填满父容器
.height('100%') // 高度填满父容器
.alignItems(ItemAlign.Start) // 水平对齐方式
.justifyContent(FlexAlign.Start) // 垂直排列方式
.padding(16) // 内边距
.backgroundColor('#F5F6FA') // 背景色
.borderRadius(12) // 圆角
.border({ width: 1, color: '#EEEEEE' }) // 边框
12.4 嵌套 Column 的最佳实践
当需要多层嵌套时,每层 Column 可以独立设置对齐方式:
Column() { // 外层:Start
Column() { // 内层:Center(覆盖外层)
Text('居中的内容')
}
.width('100%')
.alignItems(ItemAlign.Center)
Column() { // 内层:继承外层的 Start
Text('左对齐的内容')
}
.width('100%')
// 未设置 alignItems,继承外层 Column 的 ItemAlign.Start
}
.width('100%')
.alignItems(ItemAlign.Start)
13. 常见问题与调试技巧
13.1 子组件没有按预期对齐
症状:设置了 alignItems(ItemAlign.Start),但子组件没有左对齐。
原因排查:
-
子组件设置了固定宽度:如果子组件宽度 = 父容器宽度,那么 Start/Center/End 的效果看起来完全一样
- 解决:给子组件设置一个小于父容器的宽度,或使用
width('auto')
- 解决:给子组件设置一个小于父容器的宽度,或使用
-
子组件使用了
.width('100%'):这和原因 1 一样,填满了就没有对齐空间了- 解决:对于需要左对齐的组件,去掉
.width('100%'),或者只给内容所需宽度
- 解决:对于需要左对齐的组件,去掉
-
在 Row 容器中设置了 alignItems:
Row的alignItems控制垂直方向(Cross Axis),不是水平方向- 解决:
Row中使用alignItems(VerticalAlign.Center)控制垂直居中
- 解决:
13.2 高度为 0 的问题
症状:Column 容器内没有组件时高度为 0,背景颜色不显示。
原因:Column 的高度默认由子组件撑起。没有子组件或子组件高度为 0 时,Column 高度为 0。
解决:
.height('100%') // 填满父容器
// 或
.constraintSize({ minHeight: 200 }) // 设置最小高度
13.3 超出屏幕无法滚动
症状:Column 内子组件过多,超出屏幕高度无法显示。
解决:使用 Scroll 包裹 Column,使页面可滚动:
Scroll() {
Column() {
// 很多子组件...
}
.width('100%')
}
.width('100%')
.height('100%')
.scrollBar(BarState.Off) // 可选:隐藏滚动条
13.4 Column 嵌套卡顿
症状:多层 Column 嵌套导致 UI 卡顿。
原因:过多的布局嵌套增加了布局计算的开销。
建议:
- 嵌套不超过 3-4 层
- 尽量使用
@Builder拆分子布局 - 列表使用
ForEach+ 卡片组件,避免单个 Column 包含上百个节点 - 考虑使用
ListItem+List组件优化长列表性能
13.5 调试工具使用
HarmonyOS NEXT 的 DevEco Studio 提供了强大的布局调试工具:
- Inspector(预览检查器):在 Previewer 中点击组件,查看其布局属性
- 布局边界绘制:在开发者选项中开启「显示布局边界」,直观看到每个组件的 padding、margin
- console.info 日志:在生命周期回调中打印日志,确认组件加载状态
aboutToAppear(): void {
console.info('[ColumnStartDemo] 页面初始化完成');
}
14. 结语
14.1 全文回顾
本文通过一个完整可运行的 HarmonyOS NEXT 应用,深入讲解了 ColumnStart 垂直排列布局 的核心概念、配置方法和实际应用。
三个关键知识点:
- Column 容器:ArkTS 中最基础的垂直布局容器,子组件沿垂直方向排列
- alignItems(ItemAlign.Start):控制子组件在水平方向左对齐
- justifyContent(FlexAlign.Start):控制子组件在垂直方向顶部对齐
三个实战场景:
| 场景 | 布局特点 | 关键组件 |
|---|---|---|
| 信息流列表 | 双层 ColumnStart,每张卡片内部左对齐 | Column + ForEach + @Builder |
| 表单页面 | 标签在上、输入框在下,左对齐 | Column + TextInput + Button |
| 番茄钟 | Column 居中布局,Canvas 绘制 | Column + Canvas + setInterval |
14.2 布局选择指南
在实际项目中,应该如何选择布局方式?
需要什么布局? → 使用什么容器?
─────────────────────────────────────────
垂直排列,顶部对齐 → Column + alignItems(Start)
垂直排列,居中 → Column + alignItems(Center)
垂直排列,左对齐+拉伸 → Column + alignItems(Stretch)
水平排列,左对齐 → Row + alignItems(Center)
水平排列,两端对齐 → Row + justifyContent(SpaceBetween)
网格布局 → Grid / GridRow
层叠布局 → Stack
灵活弹性布局 → Flex
14.3 从本示例延伸
掌握了 ColumnStart 布局之后,你可以:
- 修改
alignItems和justifyContent的值,观察布局变化 - 在内层卡片中尝试不同的对齐方式组合
- 将信息流卡片替换为实际业务数据
- 添加下拉刷新、上拉加载等功能
- 使用
@Component将卡片抽取为独立的组件文件
14.4 完整代码获取
本文所有源代码均位于项目的以下文件中:
- 首页(番茄钟):
entry/src/main/ets/pages/Index.ets - 布局演示页:
entry/src/main/ets/pages/ColumnStartDemo.ets - 页面路由:
entry/src/main/resources/base/profile/main_pages.json - 应用配置:
AppScope/app.json5 - SDK 配置:
build-profile.json5
将项目导入 DevEco Studio 后,即可编译运行到 HarmonyOS NEXT 真机或模拟器上查看效果。
本文基于 HarmonyOS NEXT 6.1.1(API 24)Stage 模型编写
所有代码均通过 DevEco Studio 编译验证
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.
// An highlighted block
var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
| 项目 | Value |
|---|---|
| 电脑 | $1600 |
| 手机 | $12 |
| 导管 | $1 |
设定内容居中、居左、居右
使用:---------:居中
使用:----------居左
使用----------:居右
| 第一列 | 第二列 | 第三列 |
|---|---|---|
| 第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants 是一个文本转换工具,主要功能是将普通的 ASCII 标点符号自动转换为更美观的印刷体标点符号。例如:
| 原始符号 | 转换后 | 说明 |
|---|---|---|
"引号" |
“引号” | 直引号变弯引号 |
'单引号' |
‘单引号’ | 直单引号变弯单引号 |
-- |
– | 两个连字符变短破折号 |
--- |
— | 三个连字符变长破折号 |
... |
… | 三个点变省略号 |
创建一个自定义列表
-
Markdown
- Text-to- HTML conversion tool Authors
- John
- Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
新的甘特图功能,丰富你的文章
- 关于 甘特图 语法,参考 这儿,
UML图表
可以使用UML图表进行渲染,例如下面产生的一个序列图:
- 关于 UML图表 语法,参考 这儿,
流程图
- 关于 Mermaid 语法,参考 这儿,
FLowchart流程图
我们依旧会支持flowchart.js的流程图语法:
- 关于 Flowchart流程图 语法,参考 这儿.
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
-
注脚的解释 ↩︎
更多推荐



所有评论(0)