文章目录反向排列不是奇技淫巧RowReverse 和 ColumnReverse 的原理完整 DemoRowReverse 用于聊天气泡的优雅之处小结反向排列不是奇技淫巧很多人看到RowReverse和ColumnReverse就想跳过觉得这是偏门属性用不到。实际上反向排列在几个特定场景里是最简洁的解法聊天气泡自己发的消息在右边别人发的在左边。用RowReverse处理自己的消息结构和样式完全复用只改排列方向时间轴双向排列奇数条目和偶数条目分别在左右两侧像产品发布时间线从下往上的消息流消息从底部往上堆最新的在最底部。用ColumnReverse配合Scroll可以轻松实现在 PC 端时间轴双向排列比手机端更常见因为 PC 屏幕足够宽可以左右展开。RowReverse 和 ColumnReverse 的原理direction: FlexDirection.RowReverse把水平排列的起始端改到右边所有子项从右到左排列。正常 Row [A] [B] [C] ←→ [A][B][C] 左→右 RowReverse [C][B][A] 右→左ColumnReverse同理垂直排列方向从上往下变成从下往上。完整 Demo新建文件PcFlexDirectionPage.etsinterfaceChatMessage{id:numbercontent:stringtime:stringisSelf:boolean// true自己发false对方发status:string// sent | delivered | read}interfaceTimelineEvent{id:numberyear:stringtitle:stringdesc:stringcolor:stringisLeft:boolean// true显示在左侧}EntryComponentstruct PcFlexDirectionPage{StateactiveTab:number0privatemessages:ChatMessage[][{id:1,content:嘿最近在研究 HarmonyOS PC 端开发,time:10:30,isSelf:false,status:read},{id:2,content:我也是刚刚把 Flex 布局搞明白了感觉 RowReverse 挺有意思的,time:10:31,isSelf:true,status:read},{id:3,content:对聊天气泡用 RowReverse 实现自己的消息靠右真的很巧妙,time:10:32,isSelf:false,status:read},{id:4,content:比起给每条消息判断 alignSelf直接 direction 反一下简洁多了,time:10:33,isSelf:true,status:delivered},{id:5,content:PC 端还可以用这个做时间轴的左右交替布局,time:10:34,isSelf:false,status:read},{id:6,content:嗯今晚试试看感谢分享,time:10:35,isSelf:true,status:sent},]privatetimeline:TimelineEvent[][{id:1,year:2019,title:HarmonyOS 1.0 发布,desc:鸿蒙操作系统正式发布首先应用于智慧屏产品,color:#0A59F7,isLeft:true},{id:2,year:2020,title:HarmonyOS 2.0 Beta,desc:手机版正式对外发布 Beta 版本生态开始扩展,color:#00B578,isLeft:false},{id:3,year:2021,title:面向手机正式发布,desc:HarmonyOS 2.0 正式版推出超过 1 亿台设备升级,color:#FF7A00,isLeft:true},{id:4,year:2023,title:HarmonyOS 4.0,desc:全面革新交互设计性能大幅提升PC 端支持增强,color:#8B5CF6,isLeft:false},{id:5,year:2024,title:HarmonyOS NEXT,desc:纯鸿蒙系统不再兼容安卓应用生态全面独立,color:#EF4444,isLeft:true},]build(){Column(){// ── 标题 ──Text(FlexDirection 反向排列演示).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#1A1A1A).padding({left:24,top:20,bottom:4}).alignSelf(ItemAlign.Start)// ── Tab 切换 ──Row({space:8}){ForEach([聊天气泡RowReverse,时间轴ColumnReverse],(tab:string,index:number){Text(tab).fontSize(14).fontColor(this.activeTabindex?#0A59F7:#666666).fontWeight(this.activeTabindex?FontWeight.Bold:FontWeight.Normal).padding({left:16,right:16,top:7,bottom:7}).backgroundColor(this.activeTabindex?#EBF2FF:transparent).borderRadius(20).onClick((){this.activeTabindex})})}.width(100%).padding({left:16,right:16,top:8,bottom:8})Divider().color(#EEEEEE)Scroll(){Column(){if(this.activeTab0){this.buildChatDemo()}else{this.buildTimelineDemo()}}.padding({bottom:24})}.layoutWeight(1).scrollBar(BarState.Auto)}.width(100%).height(100%).backgroundColor(#F5F6F8)}// ── 聊天气泡演示RowReverse──BuilderbuildChatDemo(){Column({space:0}){// 说明卡Column({space:6}){Text(RowReverse 实现聊天气泡).fontSize(14).fontWeight(FontWeight.Bold).fontColor(#1A1A1A)Text(自己发的消息isSelftrue用 FlexDirection.RowReverse头像和内容自动靠右代码结构和对方消息完全一样).fontSize(13).fontColor(#666666).lineHeight(20)}.width(100%).padding(16).backgroundColor(#EBF2FF).margin({bottom:8})// 聊天消息列表Column({space:12}){ForEach(this.messages,(msg:ChatMessage){this.buildChatBubble(msg)})}.padding({left:16,right:16,top:12,bottom:12}).backgroundColor(#FFFFFF)}}// ── 聊天气泡 ──BuilderbuildChatBubble(msg:ChatMessage){// 关键isSelf 时用 RowReverse头像和内容自动到右边Flex({direction:msg.isSelf?FlexDirection.RowReverse:FlexDirection.Row,alignItems:ItemAlign.End}){// 头像无论正向反向这个 Column 的位置由 direction 决定Column().width(36).height(36).backgroundColor(msg.isSelf?#0A59F7:#DDDDDD).borderRadius(18)// 气泡内容Column({space:4}){Text(msg.content).fontSize(14).fontColor(msg.isSelf?#FFFFFF:#1A1A1A).lineHeight(22).padding({left:12,right:12,top:8,bottom:8}).backgroundColor(msg.isSelf?#0A59F7:#F0F0F0).borderRadius(msg.isSelf?{topLeft:12,topRight:4,bottomLeft:12,bottomRight:12}:{topLeft:4,topRight:12,bottomLeft:12,bottomRight:12}).width(280)// 时间 状态Row({space:4}){Text(msg.time).fontSize(11).fontColor(#CCCCCC)if(msg.isSelf){Text(msg.statusread?已读:msg.statusdelivered?已送达:发送中).fontSize(10).fontColor(#AAAAAA)}}.padding({left:4,right:4})}.margin({left:msg.isSelf?0:8,right:msg.isSelf?8:0}).alignItems(msg.isSelf?HorizontalAlign.End:HorizontalAlign.Start)}.width(100%)}// ── 时间轴演示双向布局──BuilderbuildTimelineDemo(){Column({space:0}){// 说明卡Column({space:6}){Text(时间轴双向布局).fontSize(14).fontWeight(FontWeight.Bold).fontColor(#1A1A1A)Text(奇数条目内容在左偶数条目内容在右通过 isLeft 属性控制中间共用一根时间线).fontSize(13).fontColor(#666666).lineHeight(20)}.width(100%).padding(16).backgroundColor(#EBF2FF).margin({bottom:8})// 时间轴Column({space:0}){ForEach(this.timeline,(event:TimelineEvent,index:number){this.buildTimelineItem(event,indexthis.timeline.length-1)})}.padding({left:16,right:16,top:16,bottom:16}).backgroundColor(#FFFFFF)}}// ── 时间轴条目 ──BuilderbuildTimelineItem(event:TimelineEvent,isLast:boolean){Row({space:0}){// 左侧内容区isLefttrue 时显示if(event.isLeft){Column({space:4}){Text(event.year).fontSize(13).fontColor(#AAAAAA).alignSelf(ItemAlign.End)Text(event.title).fontSize(15).fontColor(#1A1A1A).fontWeight(FontWeight.Bold).alignSelf(ItemAlign.End)Text(event.desc).fontSize(13).fontColor(#666666).lineHeight(20).textAlign(TextAlign.End)}.layoutWeight(1).padding({right:16,bottom:20}).alignItems(HorizontalAlign.End)}else{Column().layoutWeight(1)}// 中间节点 竖线Column(){Column().width(14).height(14).backgroundColor(event.color).borderRadius(7).border({width:2,color:#FFFFFF}).shadow({radius:4,color:${event.color}40,offsetX:0,offsetY:0})if(!isLast){Column().width(2).height(60).backgroundColor(#E0E0E0)}}.width(30).alignItems(HorizontalAlign.Center)// 右侧内容区isLeftfalse 时显示if(!event.isLeft){Column({space:4}){Text(event.year).fontSize(13).fontColor(#AAAAAA)Text(event.title).fontSize(15).fontColor(#1A1A1A).fontWeight(FontWeight.Bold)Text(event.desc).fontSize(13).fontColor(#666666).lineHeight(20)}.layoutWeight(1).padding({left:16,bottom:20}).alignItems(HorizontalAlign.Start)}else{Column().layoutWeight(1)}}.width(100%).alignItems(VerticalAlign.Top)}}RowReverse 用于聊天气泡的优雅之处传统做法给自己的消息写一套布局给对方的消息写另一套// ❌ 冗余写法if(msg.isSelf){// 右对齐布局Row(){// 内容 头像内容在左头像在右}}else{// 左对齐布局Row(){// 头像 内容头像在左内容在右}}RowReverse 写法只需一套// ✅ RowReverse 写法Flex({direction:msg.isSelf?FlexDirection.RowReverse:FlexDirection.Row}){头像()内容()// isSelftruedirectionRowReverse顺序变为 内容 头像靠右// isSelffalsedirectionRow顺序为 头像 内容靠左}代码量减半逻辑也更清晰。小结RowReverse和ColumnReverse最适合的场景聊天气泡自己/对方的消息只改排列方向代码复用时间轴双向PC 端时间轴左右交替中间共用连接线RTL从右到左语言阿拉伯语等语言方向相反一个属性搞定记住这几个场景遇到就用不必强行用transform或复制代码来实现相同效果。