HarmonyOS6 FlexWrap 实战:技术标签云为什么不要写死一行

HarmonyOS6 FlexWrap 实战:技术标签云为什么不要写死一行 文章目录标签云的核心需求直接看实现Wrap 解决的是不确定性状态更新的小细节小结标签云是一个特别容易暴露布局问题的组件。标签长度不一样数量也不固定。今天是 8 个标签明天产品说要加到 18 个中文标签还好一旦混进TypeScript、HarmonyOS、iOS/Swift这种长文本写死一行基本就崩了。这时候就该用FlexWrap.Wrap。它能让子项在主轴空间不足时自动换行非常适合标签、筛选条件、兴趣选择这类场景。标签云的核心需求这个页面做的是“选择感兴趣的技术标签”它有几个典型需求标签数量多需要自动换行点击后要切换选中状态选中标签要显示勾选标识和高亮边框底部实时展示已选内容至少选择 3 个后确认按钮才可用。布局和状态都不复杂但组合起来很贴近真实业务。直接看实现最关键的是Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap })。/** * Flex wrap标签云布局 * 知识点FlexWrap.Wrap 换行多行标签自适应排列 */interfaceTagItem{id:numberlabel:stringselected:booleancategory:stringcolor:stringbgColor:string}EntryComponentstruct FlexTagCloudPage{StatetagList:TagItem[][{id:1,label:JavaScript,selected:false,category:前端,color:#F7A400,bgColor:#FFF8E8},{id:2,label:TypeScript,selected:true,category:前端,color:#3178C6,bgColor:#EAF3FF},{id:3,label:ArkTS,selected:true,category:鸿蒙,color:#007DFF,bgColor:#EAF3FF},{id:4,label:HarmonyOS,selected:false,category:鸿蒙,color:#FF4D4D,bgColor:#FFF0F0},{id:5,label:Vue.js,selected:false,category:前端,color:#42B883,bgColor:#EDFAF4},{id:6,label:React,selected:false,category:前端,color:#61DAFB,bgColor:#E8FBFF},{id:7,label:数据结构,selected:false,category:基础,color:#9B59B6,bgColor:#F5EEFF},{id:8,label:算法,selected:true,category:基础,color:#E67E22,bgColor:#FFF4EC},{id:9,label:Git,selected:false,category:工具,color:#F05032,bgColor:#FFF0EC},{id:10,label:Docker,selected:false,category:工具,color:#2496ED,bgColor:#EAF5FF},{id:11,label:Android,selected:false,category:移动,color:#3DDC84,bgColor:#EBFEF4},{id:12,label:iOS/Swift,selected:false,category:移动,color:#FA7343,bgColor:#FFF2EC},{id:13,label:Node.js,selected:false,category:后端,color:#339933,bgColor:#EDFAED},{id:14,label:Python,selected:false,category:后端,color:#3776AB,bgColor:#EAF3FF},{id:15,label:机器学习,selected:false,category:AI,color:#FF6B6B,bgColor:#FFF0F0},{id:16,label:UI设计,selected:false,category:设计,color:#FF61B8,bgColor:#FFF0F8},{id:17,label:产品思维,selected:false,category:设计,color:#8E44AD,bgColor:#F8EEFF},{id:18,label:SQL,selected:false,category:数据库,color:#4479A1,bgColor:#EAF3FF},]privategetselectedCount():number{returnthis.tagList.filter(tt.selected).length}privategetselectedLabels():string{returnthis.tagList.filter(tt.selected).map(tt.label).join(、)}toggleTag(id:number):void{constidxthis.tagList.findIndex(tt.idid)if(idx0){constupdatedthis.tagList[idx]updated.selected!updated.selectedthis.tagList[idx]updatedthis.tagListthis.tagList.slice()}}build(){Column({space:0}){Column({space:4}){Text(选择你感兴趣的技术标签).fontSize(20).fontWeight(FontWeight.Bold).fontColor(#1A1A1A)Text(已选 this.selectedCount 个标签至少选择 3 个).fontSize(14).fontColor(this.selectedCount3?#07C160:#FF8C00)}.padding({left:16,right:16,top:24,bottom:20}).alignItems(HorizontalAlign.Start).width(100%)Flex({direction:FlexDirection.Row,wrap:FlexWrap.Wrap,alignContent:FlexAlign.Start}){ForEach(this.tagList,(tag:TagItem){Row({space:6}){if(tag.selected){Text(✓).fontSize(12).fontColor(tag.color).fontWeight(FontWeight.Bold)}Text(tag.label).fontSize(14).fontColor(tag.selected?tag.color:#666666).fontWeight(tag.selected?FontWeight.Medium:FontWeight.Normal)}.padding({left:14,right:14,top:8,bottom:8}).backgroundColor(tag.selected?tag.bgColor:#FFFFFF).borderRadius(20).border({width:1.5,color:tag.selected?tag.color:#E8E8E8}).margin({right:10,bottom:10}).onClick((){this.toggleTag(tag.id)})})}.padding({left:16,right:16}).width(100%)Blank()Column({space:10}){if(this.selectedCount0){Column({space:6}){Text(已选).fontSize(13).fontColor(#888888)Text(this.selectedLabels).fontSize(14).fontColor(#1A1A1A).maxLines(2).textOverflow({overflow:TextOverflow.Ellipsis})}.alignItems(HorizontalAlign.Start).padding({left:14,right:14,top:12,bottom:12}).backgroundColor(#F5F5F5).borderRadius(10).width(100%)}Button(确认选择).width(100%).height(50).fontSize(16).fontWeight(FontWeight.Medium).backgroundColor(this.selectedCount3?#007DFF:#CCCCCC).borderRadius(25).enabled(this.selectedCount3)}.padding({left:16,right:16,bottom:32})}.width(100%).height(100%).backgroundColor(#F5F6FA)}}Wrap 解决的是不确定性标签云最大的麻烦是不确定。你不知道标签会有几个也不知道每个标签有多长更不知道用户手机屏幕宽度是多少。FlexWrap.Wrap的价值就在这里空间够就继续横向排空间不够就自动换到下一行。这比手动计算每行放几个标签靠谱得多也更符合 ArkUI 声明式 UI 的写法。状态更新的小细节toggleTag修改选中状态后又写了一句this.tagListthis.tagList.slice()这不是多余操作。数组内部对象的属性变化有时候不一定触发你期望的 UI 刷新。重新赋一个新数组引用可以让状态变化更明确。这类写法在列表选择、购物车勾选、筛选条件切换里都很常见。小结只要遇到“数量不固定、宽度不固定、需要自动换行”的布局就优先考虑FlexWrap.Wrap。标签云只是一个例子搜索历史、筛选条件、技能标签、兴趣选择都能用这套思路。