《多级标签并行筛选》二、Grid网格布局使用指南
HarmonyOS ArkUI 网格布局Grid/GridItem从入门到实战完整指南本文系统讲解 HarmonyOS ArkUI 中 Grid 网格布局的使用方法涵盖核心属性、模板配置、跨行跨列、滚动优化等知识点并附带完整示例代码帮助开发者快速掌握 Grid 组件。效果一、前言在应用开发中卡片列表、图片画廊、商品展示等场景非常常见。这些场景的共同特点是内容以二维网格形式排列每个单元格结构相似但数据不同。传统做法是用RowColumn嵌套实现或者用Flex配合手动计算但这种方式在列数固定、需要滚动懒加载、跨行跨列等场景下代码复杂且性能不佳。Grid 网格布局正是为这类场景量身打造的容器组件。它原生支持行列模板、间距控制、滚动懒加载等能力是构建二维网格界面的首选方案。二、Grid 基础用法2.1 最简单的网格Grid(){ForEach(itemList,(item:string){GridItem(){Text(item).width(100%).height(100).backgroundColor(#F2F3F5).textAlign(TextAlign.Center)}})}.columnsTemplate(1fr 1fr)// 两列等宽.rowsGap(10)// 行间距 10.columnsGap(10)// 列间距 10.padding(16)关键点Grid是网格容器GridItem是每个网格单元columnsTemplate定义列数和列宽rowsGap/columnsGap控制行列间距2.2 GridItem 必须是 Grid 的直接子组件// 正确Grid(){GridItem(){...}GridItem(){...}}// 错误 - GridItem 不能嵌套在其他容器中Grid(){Column(){GridItem(){...}// 不会生效}}三、列模板配置3.1 等宽列// 两列等宽.columnsTemplate(1fr 1fr)// 三列等宽.columnsTemplate(1fr 1fr 1fr)// 四列等宽.columnsTemplate(1fr 1fr 1fr 1fr)fr是 fraction分数单位1fr表示一份可用空间。3.2 不等宽列// 第一列占 1 份第二列占 2 份.columnsTemplate(1fr 2fr)// 固定宽度 弹性宽度.columnsTemplate(100vp 1fr)// 混合使用.columnsTemplate(80vp 1fr 1fr)3.3 自动列数// 根据容器宽度自动计算列数每列最小 150vp.columnsTemplate(repeat(auto-fit, minmax(150vp, 1fr)))适用场景响应式布局在不同屏幕宽度下自动调整列数。四、行模板配置4.1 自动行高默认默认情况下每行高度由该行中最高的 GridItem 决定Grid(){GridItem(){Column(){Text(标题).fontSize(16)Text(描述).fontSize(12)}}// 行高自动适配内容}4.2 固定行高.rowsTemplate(100vp 120vp 100vp)// 三行固定高度4.3 等高行// 每行等高.rowsTemplate(repeat(auto-fill, 120vp))五、跨行跨列GridItem 支持跨越多个行列适用于特殊布局需求5.1 跨列Grid(){// 横跨两列的 BannerGridItem(){Text(Banner).width(100%).height(80).backgroundColor(#4A90D9)}.columnStart(0).columnEnd(2)// 从第 0 列到第 2 列不包含第 2 列GridItem(){Text(卡片1)}GridItem(){Text(卡片2)}}.columnsTemplate(1fr 1fr)5.2 跨行GridItem(){Text(纵向大卡片)}.rowStart(0).rowEnd(2)// 跨越两行5.3 使用 columnEnd/rowEnd 的另一种写法GridItem(){Text(跨两列)}.gridColumnStart(0).gridColumnEnd(2)注意跨行跨列需要配合rowsTemplate或columnsTemplate使用且 Grid 需要能计算出明确的行列结构。六、对齐与间距6.1 Grid 级间距Grid(){// ...}.rowsGap(12)// 行间距 12vp.columnsGap(12)// 列间距 12vp6.2 GridItem 对齐Grid(){GridItem(){Text(居中)}.justifyContent(FlexAlign.Center)// 主轴居中.alignContent(Alignment.Center)// 交叉轴居中}6.3 alignListItem — 列表级对齐Grid(){// ...}.alignListItem(ListItemAlign.Center)// 所有 GridItem 居中对齐七、Grid LazyForEach性能优化在数据量较大时使用LazyForEach替代ForEach实现按需加载避免一次性创建所有子组件。7.1 实现 IDataSourceObservedV2classGridItemData{Traceid:string;Tracetitle:string;Tracecolor:string#F2F3F5;constructor(id:string,title:string,color:string){this.idid;this.titletitle;this.colorcolor;}}classGridDataSourceimplementsIDataSource{privatedata:GridItemData[][];privatelisteners:DataChangeListener[][];totalCount():number{returnthis.data.length;}getData(index:number):GridItemData{returnthis.data[index];}registerDataChangeListener(listener:DataChangeListener):void{if(this.listeners.indexOf(listener)0){this.listeners.push(listener);}}unregisterDataChangeListener(listener:DataChangeListener):void{constposthis.listeners.indexOf(listener);if(pos0){this.listeners.splice(pos,1);}}pushData(item:GridItemData):void{this.data.push(item);this.listeners.forEach(ll.onDataAdd(this.data.length-1));}clear():void{this.data[];this.listeners.forEach(ll.onDataReloaded());}}7.2 使用 LazyForEachEntryComponentV2struct LazyGridDemo{LocaldataSource:GridDataSourcenewGridDataSource();aboutToAppear():void{for(leti0;i50;i){constcolors[#4A90D9,#66BB6A,#E8A838,#AB47BC];this.dataSource.pushData(newGridItemData(g${i},项目${i1},colors[i%4]));}}build(){Grid(){LazyForEach(this.dataSource,(item:GridItemData){GridItem(){Column(){Row().width(100%).aspectRatio(1).backgroundColor(item.color).borderRadius({topLeft:10,topRight:10})Text(item.title).fontSize(13).padding({top:6,bottom:6})}.backgroundColor(#FFFFFF).borderRadius(10).shadow({radius:4,color:#1A000000})}},(item:GridItemData)item.id)}.columnsTemplate(1fr 1fr).columnsGap(12).rowsGap(12).padding(16).width(100%).height(100%)}}性能优势按需创建仅创建可见区域及缓存区的组件自动回收离开可见区域的组件被自动回收配合cachedCount控制缓存数量平衡内存和流畅度八、Grid 嵌套滚动Grid 通常放在Scroll中实现整页滚动Scroll(){Grid(){ForEach(items,(item:ItemType){GridItem(){// 卡片内容}})}.columnsTemplate(1fr 1fr).columnsGap(12).rowsGap(12).padding({left:16,right:16})}.scrollBar(BarState.Off).width(100%).height(100%)注意当 Grid 放在 Scroll 中时Grid 的高度应设为内容自适应不设置固定高度否则可能导致内部滚动冲突。九、完整示例卡片画廊interfaceGalleryItem{id:string;title:string;subtitle:string;color:string;}EntryComponentV2struct GridGalleryDemo{Localitems:GalleryItem[][{id:1,title:日出,subtitle:自然风光,color:#E8974A},{id:2,title:城市,subtitle:都市摄影,color:#4A7FB5},{id:3,title:美食,subtitle:美食摄影,color:#B5564A},{id:4,title:星空,subtitle:天文摄影,color:#2C3E6B},{id:5,title:花卉,subtitle:微距摄影,color:#C44A8A},{id:6,title:建筑,subtitle:建筑摄影,color:#5B8A4A}];build(){Column(){Text(卡片画廊).fontSize(22).fontWeight(FontWeight.Bold).padding({left:20,top:16,bottom:12}).alignSelf(ItemAlign.Start)Scroll(){Grid(){ForEach(this.items,(item:GalleryItem){GridItem(){Column(){// 封面色块Stack(){Row().width(100%).height(100%).backgroundColor(item.color)Text(item.title).fontSize(18).fontColor(#FFFFFF).fontWeight(FontWeight.Bold)}.width(100%).aspectRatio(1).borderRadius({topLeft:12,topRight:12})// 文字区域Column(){Text(item.title).fontSize(14).fontWeight(FontWeight.Medium)Text(item.subtitle).fontSize(12).fontColor(#999999).margin({top:2})}.padding({left:10,right:10,top:8,bottom:10}).width(100%).alignItems(HorizontalAlign.Start)}.backgroundColor(#FFFFFF).borderRadius(12).shadow({radius:6,color:#1A000000,offsetX:0,offsetY:2})}},(item:GalleryItem)item.id)}.columnsTemplate(1fr 1fr).columnsGap(12).rowsGap(12).padding({left:16,right:16})}.layoutWeight(1).scrollBar(BarState.Off)}.width(100%).height(100%).backgroundColor(#F5F5F5)}}十、Grid vs List vs Flex 对比场景推荐组件原因单列滚动列表List ListItem专为列表优化支持 ListItemGroup多列卡片网格Grid GridItem原生支持行列模板和跨行跨列标签/导航栏Flex一维排列 换行场景瀑布流WaterFlow不等高卡片场景固定数量卡片GridcolumnsTemplate 精确控制十一、最佳实践使用columnsTemplate精确控制列比依赖默认行为更可控。大数据量配合LazyForEach避免全量创建导致的性能问题。跨行跨列配合模板使用确保 Grid 能计算出明确的行列结构。rowsGap/columnsGap统一管理间距比手动 margin 更稳定。嵌套在 Scroll 中时不设固定高度让 Grid 自适应内容高度。使用shadow提升卡片质感配合borderRadius打造简约风格。十二、总结Grid 网格布局是 ArkUI 中处理二维排列场景的核心组件。通过columnsTemplate和rowsTemplate精确控制行列结构配合GridItem的跨行跨列能力能够灵活实现各种网格界面。结合LazyForEach进行性能优化即使在大数据量下也能保持流畅体验。参考文档创建网格 (Grid/GridItem)