文章目录
- 圆点设计:大小与层次
- 竖线设计:连接感的关键
- 状态颜色系统
- 时间标签的排版
- 空间节奏:padding 和间距的分配
- 完整代码
- 几个容易忽视的细节
- 小结
时间轴之所以让人一眼就认出来,不是因为数据本身,而是那根贯穿始终的竖线和串联在上面的节点。把这条"视觉脊梁"设计好,时间轴就有了自己的气质。
这篇专门讲视觉层:圆点怎么设计、竖线和节点的间距配合、三种状态(完成/进行中/待开始)的颜色系统,以及整体空间节奏感怎么建立。
圆点设计:大小与层次
圆点承担"节点标记"的语义,太小了视觉弱,太大了又喧宾夺主。实测 12vp 是比较舒适的默认尺寸,在 HarmonyOS PC 端的 100% 缩放比下对应物理尺寸大约 4mm,手指点击完全没问题。
"进行中"状态的圆点可以比其他圆点稍大一圈,同时加一个外圈光晕,强调当前焦点:
// 进行中:16vp 圆点 + 外圈光晕Circle({width:16,height:16}).fill('#3B82F6').shadow({radius:8,color:'#403B82F6'})// 蓝色光晕,40% 透明度// 已完成:12vp 实心Circle({width:12,height:12}).fill('#10B981')// 待开始:12vp 空心(边框实现)Circle({width:12,height:12}).fill(Color.White).border({width:2,color:'#D1D5DB'})三种状态视觉强度递减:进行中 > 已完成 > 待开始。用户扫一眼就能找到"当前在哪里"。
竖线设计:连接感的关键
竖线的颜色别用纯黑或纯白,用带透明度的灰色更柔和:
Divider().vertical(true).strokeWidth(2).color('#E5E7EB')// Tailwind gray-200,刚好够可见但不抢眼竖线的高度要刚好衔接上下两个圆点。如果用固定高度,当内容区文字折行时,竖线就会对不上。
比较稳的方案是让右侧内容区决定高度,竖线跟着自适应:
Row({space:16}){// 左侧轨道:竖线跟内容高度走Column(){Circle(...)Divider().vertical(true).layoutWeight(1)// ← layoutWeight(1) 自适应}.alignItems(HorizontalAlign.Center).height('100%')// ← 撑满 Row 的高度// 右侧内容区:决定整行高度Column(...){...}.layoutWeight(1).padding({bottom:24})// ← 底部留白决定竖线长度感}.alignItems(VerticalAlign.Top)这样不管右侧内容折不折行,竖线都能准确填满空间。
状态颜色系统
用三色体系,每种颜色负责一种语义:
| 状态 | 颜色 | Hex | 语义 |
|---|---|---|---|
| 已完成 | 绿色 | #10B981 | 积极、完成 |
| 进行中 | 蓝色 | #3B82F6 | 活跃、当前 |
| 待开始 | 灰色 | #D1D5DB | 中性、未激活 |
这三个颜色不是随便选的。绿和蓝在 HarmonyOS 的设计规范里是正向操作的标准色,灰色是禁用/未激活的标准色。用系统已有的色彩语义,用户不需要额外学习就能看懂。
时间标签的排版
时间字段通常是YYYY-MM-DD格式,12px 字号,靠右对齐,颜色比描述文字更浅:
Text(item.time).fontSize(12).fontColor('#9CA3AF')// 比描述文字的 #6B7280 更浅时间标签和标题放在同一行,时间靠右,标题靠左,用layoutWeight(1)推开:
Row(){Text(item.title).fontSize(15).fontWeight(FontWeight.Medium).layoutWeight(1)Text(item.time).fontSize(12).fontColor('#9CA3AF')}.width('100%')空间节奏:padding 和间距的分配
时间轴的空间节奏主要靠两个参数控制:
- 条目内的底部 padding:决定"竖线有多长",也就是条目间的间距感。设 24vp。
- 内容区内的行间距:标题和描述的间距,设 4vp,显得紧凑。
// 条目间距:底部 padding 拉开间距Column({space:4}){Row(){...}// 标题行Text(desc)...// 描述}.padding({bottom:24})整个时间轴容器两侧各留 32vp 的水平 padding,给圆点轨道留足空间,同时让内容区不至于顶边。
完整代码
enumTimelineStatus{Done,Active,Pending}classTimelineItem{time:stringtitle:stringdesc:stringstatus:TimelineStatusconstructor(time:string,title:string,desc:string,status:TimelineStatus){this.time=timethis.title=titlethis.desc=descthis.status=status}}@Entry@Componentstruct PcTimelineVisualPage{@Stateitems:TimelineItem[]=[newTimelineItem('2019-08-09','HarmonyOS 正式发布','华为在开发者大会上正式发布 HarmonyOS,开启万物互联新时代。',TimelineStatus.Done),newTimelineItem('2021-06-02','HarmonyOS 2.0 发布','面向手机用户正式发布,分布式技术全面落地,首批适配机型超过百款。',TimelineStatus.Done),newTimelineItem('2022-07-27','HarmonyOS 3.0 发布','超级终端体验升级,跨设备协同能力大幅增强,平板/PC 体验全面优化。',TimelineStatus.Done),newTimelineItem('2023-08-04','HarmonyOS 4.0 发布','引入星盾安全架构,AI 融合能力升级,PC 端窗口管理体验全新改版。',TimelineStatus.Done),newTimelineItem('2024-10-22','HarmonyOS Next 发布','全面去安卓兼容,纯血 HarmonyOS 正式亮相,ArkTS 生态全面成熟。',TimelineStatus.Active),newTimelineItem('2025 Q2','HarmonyOS PC 版全量推送','PC 端 HarmonyOS 生态完善,应用商店 PC 专属分区上线,开发者工具链更新。',TimelineStatus.Pending)]getStatusColor(status:TimelineStatus):string{switch(status){caseTimelineStatus.Done:return'#10B981'caseTimelineStatus.Active:return'#3B82F6'caseTimelineStatus.Pending:return'#D1D5DB'default:return'#D1D5DB'}}getNodeSize(status:TimelineStatus):number{returnstatus===TimelineStatus.Active?16:12}getNodeShadow(status:TimelineStatus):string{returnstatus===TimelineStatus.Active?'#403B82F6':'transparent'}@BuildertimelineNode(status:TimelineStatus,isLast:boolean){Column(){// 节点圆点Stack(){if(status===TimelineStatus.Pending){Circle({width:this.getNodeSize(status),height:this.getNodeSize(status)}).fill(Color.White).border({width:2,color:'#D1D5DB'})}else{Circle({width:this.getNodeSize(status),height:this.getNodeSize(status)}).fill(this.getStatusColor(status)).shadow({radius:8,color:this.getNodeShadow(status)})}}.width(24).height(this.getNodeSize(status))// 连接线(非最后一项)if(!isLast){Divider().vertical(true).layoutWeight(1).strokeWidth(2).color('#E5E7EB')}}.width(24).alignItems(HorizontalAlign.Center).height('100%')}@BuildertimelineContent(item:TimelineItem){Column({space:4}){Row(){Text(item.title).fontSize(15).fontWeight(FontWeight.Medium).fontColor(item.status===TimelineStatus.Active?'#1E40AF':'#1F2937').layoutWeight(1)Text(item.time).fontSize(12).fontColor('#9CA3AF')}.width('100%')Text(item.desc).fontSize(13).fontColor('#6B7280').lineHeight(20).width('100%')if(item.status===TimelineStatus.Active){Row({space:6}){Circle({width:6,height:6}).fill('#3B82F6')Text('进行中').fontSize(11).fontColor('#3B82F6').fontWeight(FontWeight.Medium)}.margin({top:4}).padding({left:8,right:8,top:4,bottom:4}).backgroundColor('#EFF6FF').borderRadius(12)}}.layoutWeight(1).padding({bottom:28}).alignItems(HorizontalAlign.Start)}@BuildertimelineItem(item:TimelineItem,isLast:boolean){Row({space:16}){this.timelineNode(item.status,isLast)this.timelineContent(item)}.alignItems(VerticalAlign.Top).width('100%')}build(){Scroll(){Column({space:0}){// 标题区Column({space:8}){Text('HarmonyOS 发展历程').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#111827')Text('从发布到今天,记录每一个关键里程碑').fontSize(14).fontColor('#6B7280')// 图例Row({space:20}){Row({space:6}){Circle({width:8,height:8}).fill('#10B981')Text('已发布').fontSize(12).fontColor('#6B7280')}Row({space:6}){Circle({width:8,height:8}).fill('#3B82F6')Text('进行中').fontSize(12).fontColor('#6B7280')}Row({space:6}){Circle({width:8,height:8}).fill(Color.White).border({width:1,color:'#D1D5DB'})Text('待发布').fontSize(12).fontColor('#6B7280')}}.margin({top:8})}.padding({left:32,right:32,top:32,bottom:24}).alignItems(HorizontalAlign.Start).width('100%').backgroundColor(Color.White)Divider().strokeWidth(1).color('#F3F4F6')// 时间轴Column(){ForEach(this.items,(item:TimelineItem,index:number)=>{this.timelineItem(item,index===this.items.length-1)})}.padding({left:32,right:32,top:32,bottom:32}).backgroundColor(Color.White).margin({top:16})}.constraintSize({minWidth:600,maxWidth:860}).margin({left:'auto',right:'auto'})}.width('100%').height('100%').backgroundColor('#F9FAFB')}}几个容易忽视的细节
1. "进行中"状态的标题颜色
正在进行的事件是当前焦点,标题颜色用稍深的蓝色#1E40AF,和其他条目的深灰#1F2937形成区分。用户不用细看颜色分类图例就能找到"现在在这里"。
2. 状态胶囊只给"进行中"加
不要给每个状态都加胶囊标签。"已完成"靠绿色圆点传递语义,"待开始"靠灰色传递,"进行中"因为是焦点,值得多一点视觉强调。加多了反而乱。
3. 描述文字的行高
lineHeight(20)比默认行高稍大,让多行文字阅读更舒适。PC 端内容多,这个细节值得设。
小结
时间轴的视觉设计其实就是在管理"注意力层级":哪个条目最重要(进行中),哪些已经完成(绿点),哪些还没到(灰色空心)。颜色、大小、阴影这些视觉属性,每一个都在为这个层级服务。
把这套方法论迁移到其他场景——步骤条、审批流程、版本历史——都是一样的逻辑。