# åˆ›å»ºç½‘æ ¼ (Grid/GridItem) ## 概述 ç½‘æ ¼å¸ƒå±€æ˜¯ç”±â€œè¡Œâ€å’Œâ€œåˆ—â€åˆ†å‰²çš„å•å…ƒæ ¼æ‰€ç»„æˆï¼Œé€šè¿‡æŒ‡å®šâ€œé¡¹ç›®â€æ‰€åœ¨çš„å•å…ƒæ ¼åšå‡ºå„ç§å„æ ·çš„å¸ƒå±€ã€‚ç½‘æ ¼å¸ƒå±€å…·æœ‰è¾ƒå¼ºçš„é¡µé¢å‡åˆ†èƒ½åŠ›ï¼Œå组件å 比控制能力,是一ç§é‡è¦è‡ªé€‚应布局,其使用场景有ä¹å®«æ ¼å›¾ç‰‡å±•ç¤ºã€æ—¥åŽ†ã€è®¡ç®—器ç‰ã€‚ ArkUIæ供了[Grid](../reference/apis-arkui/arkui-ts/ts-container-grid.md)容器组件和å组件[GridItem](../reference/apis-arkui/arkui-ts/ts-container-griditem.md)ï¼Œç”¨äºŽæž„å»ºç½‘æ ¼å¸ƒå±€ã€‚Gridç”¨äºŽè®¾ç½®ç½‘æ ¼å¸ƒå±€ç›¸å…³å‚数,GridItem定义å组件相关特å¾ã€‚Grid组件支æŒä½¿ç”¨[æ¡ä»¶æ¸²æŸ“](../quick-start/arkts-rendering-control-ifelse.md)ã€[循环渲染](../quick-start/arkts-rendering-control-foreach.md)ã€[æ‡’åŠ è½½](../quick-start/arkts-rendering-control-lazyforeach.md)ç‰æ–¹å¼ç”Ÿæˆå组件。 ## å¸ƒå±€ä¸Žçº¦æŸ Gridç»„ä»¶ä¸ºç½‘æ ¼å®¹å™¨ï¼Œå…¶ä¸å®¹å™¨å†…å„æ¡ç›®å¯¹åº”一个GridItem组件,如下图所示。 **图1** Grid与GridItem组件关系  >**说明:** > >Gridçš„å组件必须是GridItem组件。 ç½‘æ ¼å¸ƒå±€æ˜¯ä¸€ç§äºŒç»´å¸ƒå±€ã€‚Grid组件支æŒè‡ªå®šä¹‰è¡Œåˆ—æ•°å’Œæ¯è¡Œæ¯åˆ—尺寸å 比ã€è®¾ç½®åç»„ä»¶æ¨ªè·¨å‡ è¡Œæˆ–è€…å‡ åˆ—ï¼ŒåŒæ—¶æä¾›äº†åž‚ç›´å’Œæ°´å¹³å¸ƒå±€èƒ½åŠ›ã€‚å½“ç½‘æ ¼å®¹å™¨ç»„ä»¶å°ºå¯¸å‘生å˜åŒ–时,所有å组件以åŠé—´è·ä¼šç‰æ¯”ä¾‹è°ƒæ•´ï¼Œä»Žè€Œå®žçŽ°ç½‘æ ¼å¸ƒå±€çš„è‡ªé€‚åº”èƒ½åŠ›ã€‚æ ¹æ®Grid的这些布局能力,å¯ä»¥æž„建出ä¸åŒæ ·å¼çš„ç½‘æ ¼å¸ƒå±€ï¼Œå¦‚ä¸‹å›¾æ‰€ç¤ºã€‚ **图2** ç½‘æ ¼å¸ƒå±€Â Â  如果Grid组件设置了宽高属性,则其尺寸为设置值。如果没有设置宽高属性,Grid组件的尺寸默认适应其父组件的尺寸。 Gridç»„ä»¶æ ¹æ®è¡Œåˆ—æ•°é‡ä¸Žå 比属性的设置,å¯ä»¥åˆ†ä¸ºä¸‰ç§å¸ƒå±€æƒ…况: - è¡Œã€åˆ—æ•°é‡ä¸Žå 比åŒæ—¶è®¾ç½®ï¼šGridåªå±•ç¤ºå›ºå®šè¡Œåˆ—æ•°çš„å…ƒç´ ï¼Œå…¶ä½™å…ƒç´ ä¸å±•ç¤ºï¼Œä¸”Gridä¸å¯æ»šåŠ¨ã€‚(推è使用该ç§å¸ƒå±€æ–¹å¼ï¼‰ - åªè®¾ç½®è¡Œã€åˆ—æ•°é‡ä¸Žå 比ä¸çš„ä¸€ä¸ªï¼šå…ƒç´ æŒ‰ç…§è®¾ç½®çš„æ–¹å‘è¿›è¡ŒæŽ’å¸ƒï¼Œè¶…å‡ºçš„å…ƒç´ å¯é€šè¿‡æ»šåŠ¨çš„æ–¹å¼å±•ç¤ºã€‚ - 行列数é‡ä¸Žå 比都ä¸è®¾ç½®ï¼šå…ƒç´ 在布局方å‘上排布,其行列数由布局方å‘ã€å•ä¸ªç½‘æ ¼çš„å®½é«˜ç‰å¤šä¸ªå±žæ€§å…±åŒå†³å®šã€‚è¶…å‡ºè¡Œåˆ—å®¹çº³èŒƒå›´çš„å…ƒç´ ä¸å±•ç¤ºï¼Œä¸”Gridä¸å¯æ»šåŠ¨ã€‚ ## è®¾ç½®æŽ’åˆ—æ–¹å¼ ### 设置行列数é‡ä¸Žå 比 通过设置行列数é‡ä¸Žå°ºå¯¸å 比å¯ä»¥ç¡®å®šç½‘æ ¼å¸ƒå±€çš„æ•´ä½“æŽ’åˆ—æ–¹å¼ã€‚Grid组件æ供了rowsTemplateå’ŒcolumnsTemplateå±žæ€§ç”¨äºŽè®¾ç½®ç½‘æ ¼å¸ƒå±€è¡Œåˆ—æ•°é‡ä¸Žå°ºå¯¸å 比。 rowsTemplateå’ŒcolumnsTemplateå±žæ€§å€¼æ˜¯ä¸€ä¸ªç”±å¤šä¸ªç©ºæ ¼å’Œ'æ•°å—+fr'间隔拼接的å—符串,fr的个数å³ç½‘æ ¼å¸ƒå±€çš„è¡Œæˆ–åˆ—æ•°ï¼Œfrå‰é¢çš„数值大å°ï¼Œç”¨äºŽè®¡ç®—è¯¥è¡Œæˆ–åˆ—åœ¨ç½‘æ ¼å¸ƒå±€å®½åº¦ä¸Šçš„å 比,最终决定该行或列宽度。 **图3** 行列数é‡å 比示例  å¦‚ä¸Šå›¾æ‰€ç¤ºï¼Œæž„å»ºçš„æ˜¯ä¸€ä¸ªä¸‰è¡Œä¸‰åˆ—çš„ç½‘æ ¼å¸ƒå±€ï¼Œå…¶åœ¨åž‚ç›´æ–¹å‘上分为三ç‰ä»½ï¼Œæ¯è¡Œå 一份;在水平方å‘上分为四ç‰ä»½ï¼Œç¬¬ä¸€åˆ—å 一份,第二列å 两份,第三列å 一份。 åªè¦å°†rowsTemplate的值为'1fr 1fr 1fr',åŒæ—¶å°†columnsTemplate的值为'1fr 2fr 1fr',å³å¯å®žçŽ°ä¸Šè¿°ç½‘æ ¼å¸ƒå±€ã€‚ ```ts Grid() { ... } .rowsTemplate('1fr 1fr 1fr') .columnsTemplate('1fr 2fr 1fr') ``` >**说明:** > >当Grid组件设置了rowsTemplate或columnsTemplate时,Gridçš„layoutDirectionã€maxCountã€minCountã€cellLength属性ä¸ç”Ÿæ•ˆï¼Œå±žæ€§è¯´æ˜Žå¯å‚考[Grid-属性](../reference/apis-arkui/arkui-ts/ts-container-grid.md#属性)。 ### 设置å组件所å 行列数 除了大å°ç›¸åŒçš„ç‰æ¯”ä¾‹ç½‘æ ¼å¸ƒå±€ï¼Œç”±ä¸åŒå¤§å°çš„ç½‘æ ¼ç»„æˆä¸å‡åŒ€åˆ†å¸ƒçš„ç½‘æ ¼å¸ƒå±€åœºæ™¯åœ¨å®žé™…åº”ç”¨ä¸å分常è§ï¼Œå¦‚下图所示。在Grid组件ä¸ï¼Œå¯ä»¥é€šè¿‡åˆ›å»ºGridæ—¶ä¼ å…¥åˆé€‚çš„[GridLayoutOptions](../reference/apis-arkui/arkui-ts/ts-container-grid.md#gridlayoutoptions10对象说明)实现如图所示的å•ä¸ªç½‘æ ¼æ¨ªè·¨å¤šè¡Œæˆ–å¤šåˆ—çš„åœºæ™¯ï¼Œå…¶ä¸ï¼ŒirregularIndexeså’ŒonGetIrregularSizeByIndexå¯å¯¹ä»…设置rowsTemplate或columnsTemplateçš„Grid使用;onGetRectByIndexå¯å¯¹åŒæ—¶è®¾ç½®rowsTemplateå’ŒcolumnsTemplateçš„Grid使用。 **图4** ä¸å‡åŒ€ç½‘æ ¼å¸ƒå±€  例如计算器的按键布局就是常è§çš„ä¸å‡åŒ€ç½‘æ ¼å¸ƒå±€åœºæ™¯ã€‚å¦‚ä¸‹å›¾ï¼Œè®¡ç®—å™¨ä¸çš„按键“0â€å’Œâ€œ=â€ï¼ŒæŒ‰é”®â€œ0â€æ¨ªè·¨ç¬¬ä¸€ã€äºŒä¸¤åˆ—,按键“=â€æ¨ªè·¨ç¬¬äº”ã€å…两行。使用Gridæž„å»ºçš„ç½‘æ ¼å¸ƒå±€ï¼Œå…¶è¡Œåˆ—æ ‡å·ä»Ž0开始,ä¾æ¬¡ç¼–å·ã€‚ **图5** 计算器   åœ¨ç½‘æ ¼ä¸ï¼Œå¯ä»¥é€šè¿‡onGetRectByIndex返回的[rowStart,columnStart,rowSpan,columnSpan]æ¥å®žçŽ°è·¨è¡Œè·¨åˆ—布局,其ä¸rowStartå’ŒcolumnStart属性表示指定当å‰å…ƒç´ 起始行å·å’Œèµ·å§‹åˆ—å·ï¼ŒrowSpanå’ŒcolumnSpan属性表示指定当å‰å…ƒç´ çš„å 用行数和å 用列数。 所以“0â€æŒ‰é”®æ¨ªè·¨ç¬¬ä¸€åˆ—和第二列,“=â€æŒ‰é”®æ¨ªè·¨ç¬¬äº”行和第å…行,åªè¦å°†â€œ0â€å¯¹åº”onGetRectByIndexçš„rowStartå’ŒcolumnStart设为5å’Œ0,rowSpanå’ŒcolumnSpan设为1å’Œ2,将“=â€å¯¹åº”onGetRectByIndexçš„rowStartå’ŒcolumnStart设为4å’Œ3,rowSpanå’ŒcolumnSpan设为2å’Œ1å³å¯ã€‚ ```ts layoutOptions: GridLayoutOptions = { regularSize: [1, 1], onGetRectByIndex: (index: number) => { if (index == key1) { // key1是“0â€æŒ‰é”®å¯¹åº”çš„index return [5, 0, 1, 2] } else if (index == key2) { // key2是“=â€æŒ‰é”®å¯¹åº”çš„index return [4, 3, 2, 1] } // ... // 这里需è¦æ ¹æ®å…·ä½“布局返回其他itemçš„ä½ç½® } } Grid(undefined, this.layoutOptions) { // ... } .columnsTemplate('1fr 1fr 1fr 1fr') .rowsTemplate('2fr 1fr 1fr 1fr 1fr 1fr') ``` ### è®¾ç½®ä¸»è½´æ–¹å‘ ä½¿ç”¨Gridæž„å»ºç½‘æ ¼å¸ƒå±€æ—¶ï¼Œè‹¥æ²¡æœ‰è®¾ç½®è¡Œåˆ—æ•°é‡ä¸Žå 比,å¯ä»¥é€šè¿‡layoutDirectionè®¾ç½®ç½‘æ ¼å¸ƒå±€çš„ä¸»è½´æ–¹å‘,决定å组件的排列方å¼ã€‚æ¤æ—¶å¯ä»¥ç»“åˆminCountå’ŒmaxCount属性æ¥çº¦æŸä¸»è½´æ–¹å‘ä¸Šçš„ç½‘æ ¼æ•°é‡ã€‚ **图6** 主轴方å‘示æ„图  当å‰layoutDirection设置为Row时,先从左到å³æŽ’列,排满一行å†æŽ’下一行。当å‰layoutDirection设置为Column时,先从上到下排列,排满一列å†æŽ’下一列,如上图所示。æ¤æ—¶ï¼Œå°†maxCount属性设为3,表示主轴方å‘ä¸Šæœ€å¤§æ˜¾ç¤ºçš„ç½‘æ ¼å•å…ƒæ•°é‡ä¸º3。 ```ts Grid() { ... } .maxCount(3) .layoutDirection(GridDirection.Row) ``` >**说明:** > >- layoutDirection属性仅在ä¸è®¾ç½®rowsTemplateå’ŒcolumnsTemplate时生效,æ¤æ—¶å…ƒç´ 在layoutDirectionæ–¹å‘上排列。 >- 仅设置rowsTemplate时,Grid主轴为水平方å‘,交å‰è½´ä¸ºåž‚ç›´æ–¹å‘。 >- 仅设置columnsTemplate时,Grid主轴为垂直方å‘,交å‰è½´ä¸ºæ°´å¹³æ–¹å‘。 ## åœ¨ç½‘æ ¼å¸ƒå±€ä¸æ˜¾ç¤ºæ•°æ® ç½‘æ ¼å¸ƒå±€é‡‡ç”¨äºŒç»´å¸ƒå±€çš„æ–¹å¼ç»„ç»‡å…¶å†…éƒ¨å…ƒç´ ï¼Œå¦‚ä¸‹å›¾æ‰€ç¤ºã€‚ **图7** 通用办公æœåŠ¡Â   Grid组件å¯ä»¥é€šè¿‡äºŒç»´å¸ƒå±€çš„æ–¹å¼æ˜¾ç¤ºä¸€ç»„GridItemå组件。 ```ts Grid() { GridItem() { Text('会议') ... } GridItem() { Text('ç¾åˆ°') ... } GridItem() { Text('投票') ... } GridItem() { Text('打å°') ... } } .rowsTemplate('1fr 1fr') .columnsTemplate('1fr 1fr') ``` 对于内容结构相似的多个GridItem,通常更推è使用ForEachè¯å¥ä¸åµŒå¥—GridItemçš„å½¢å¼ï¼Œæ¥å‡å°‘é‡å¤ä»£ç 。 ```ts @Entry @Component struct OfficeService { @State services: Array<string> = ['会议', '投票', 'ç¾åˆ°', '打å°'] build() { Column() { Grid() { ForEach(this.services, (service:string) => { GridItem() { Text(service) } }, (service:string):string => service) } .rowsTemplate(('1fr 1fr') as string) .columnsTemplate(('1fr 1fr') as string) } } } ``` ## è®¾ç½®è¡Œåˆ—é—´è· åœ¨ä¸¤ä¸ªç½‘æ ¼å•å…ƒä¹‹é—´çš„ç½‘æ ¼æ¨ªå‘é—´è·ç§°ä¸ºè¡Œé—´è·ï¼Œç½‘æ ¼çºµå‘é—´è·ç§°ä¸ºåˆ—é—´è·ï¼Œå¦‚下图所示。 **图8** ç½‘æ ¼çš„è¡Œåˆ—é—´è·Â   通过Gridçš„rowsGapå’ŒcolumnsGapå¯ä»¥è®¾ç½®ç½‘æ ¼å¸ƒå±€çš„è¡Œåˆ—é—´è·ã€‚在图5所示的计算器ä¸ï¼Œè¡Œé—´è·ä¸º15vp,列间è·ä¸º10vp。 ```ts Grid() { ... } .columnsGap(10) .rowsGap(15) ``` ## 构建å¯æ»šåŠ¨çš„ç½‘æ ¼å¸ƒå±€ å¯æ»šåŠ¨çš„ç½‘æ ¼å¸ƒå±€å¸¸ç”¨åœ¨æ–‡ä»¶ç®¡ç†ã€è´ç‰©æˆ–视频列表ç‰é¡µé¢ä¸ï¼Œå¦‚下图所示。在设置Grid的行列数é‡ä¸Žå 比时,如果仅设置行ã€åˆ—æ•°é‡ä¸Žå 比ä¸çš„一个,å³ä»…设置rowsTemplate或仅设置columnsTemplateå±žæ€§ï¼Œç½‘æ ¼å•å…ƒæŒ‰ç…§è®¾ç½®çš„æ–¹å‘排列,超出Grid显示区域åŽï¼ŒGrid拥有å¯æ»šåŠ¨èƒ½åŠ›ã€‚ **图9** 横å‘å¯æ»šåŠ¨ç½‘æ ¼å¸ƒå±€  如果设置的是columnsTemplate,Grid的滚动方å‘为垂直方å‘;如果设置的是rowsTemplate,Grid的滚动方å‘为水平方å‘。 如上图所示的横å‘å¯æ»šåŠ¨ç½‘æ ¼å¸ƒå±€ï¼Œåªè¦è®¾ç½®rowsTemplate属性的值且ä¸è®¾ç½®columnsTemplate属性,当内容超出Grid组件宽度时,Gridå¯æ¨ªå‘滚动进行内容展示。 ```ts @Entry @Component struct Shopping { @State services: Array<string> = ['ç›´æ’', 'è¿›å£'] build() { Column({ space: 5 }) { Grid() { ForEach(this.services, (service: string, index) => { GridItem() { } .width('25%') }, (service:string):string => service) } .rowsTemplate('1fr 1fr') // åªè®¾ç½®rowsTemplate属性,当内容超出Grid区域时,å¯æ°´å¹³æ»šåŠ¨ã€‚ .rowsGap(15) } } } ``` ## 控制滚动ä½ç½® 与新闻列表的返回顶部场景类似,控制滚动ä½ç½®åŠŸèƒ½åœ¨ç½‘æ ¼å¸ƒå±€ä¸ä¹Ÿå¾ˆå¸¸ç”¨ï¼Œä¾‹å¦‚下图所示日历的翻页功能。 **图10** 日历翻页   Grid组件åˆå§‹åŒ–时,å¯ä»¥ç»‘定一个[Scroller](../reference/apis-arkui/arkui-ts/ts-container-scroll.md#scroller)对象,用于进行滚动控制,例如通过Scroller对象的[scrollPage](../reference/apis-arkui/arkui-ts/ts-container-scroll.md#scrollpage9)方法进行翻页。 ```ts private scroller: Scroller = new Scroller() ``` 在日历页é¢ä¸ï¼Œç”¨æˆ·åœ¨ç‚¹å‡»â€œä¸‹ä¸€é¡µâ€æŒ‰é’®æ—¶ï¼Œåº”用å“应点击事件,通过指定scrollPage方法的å‚æ•°next为true,滚动到下一页。 ```ts Column({ space: 5 }) { Grid(this.scroller) { } .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr') Row({space: 20}) { Button('上一页') .onClick(() => { this.scroller.scrollPage({ next: false }) }) Button('下一页') .onClick(() => { this.scroller.scrollPage({ next: true }) }) } } ``` ## 性能优化 与[长列表的处ç†](arkts-layout-development-create-list.md#长列表的处ç†)类似,[循环渲染](../quick-start/arkts-rendering-control-foreach.md)适用于数æ®é‡è¾ƒå°çš„布局场景,当构建具有大é‡ç½‘æ ¼é¡¹çš„å¯æ»šåŠ¨ç½‘æ ¼å¸ƒå±€æ—¶ï¼ŒæŽ¨è使用[æ•°æ®æ‡’åŠ è½½](../quick-start/arkts-rendering-control-lazyforeach.md)æ–¹å¼å®žçŽ°æŒ‰éœ€è¿ä»£åŠ 载数æ®ï¼Œä»Žè€Œæå‡åˆ—表性能。 å…³äºŽæŒ‰éœ€åŠ è½½ä¼˜åŒ–çš„å…·ä½“å®žçŽ°å¯å‚考[æ•°æ®æ‡’åŠ è½½](../quick-start/arkts-rendering-control-lazyforeach.md)ç« èŠ‚ä¸çš„示例。 å½“ä½¿ç”¨æ‡’åŠ è½½æ–¹å¼æ¸²æŸ“ç½‘æ ¼æ—¶ï¼Œä¸ºäº†æ›´å¥½çš„æ»šåŠ¨ä½“éªŒï¼Œå‡å°‘滑动时出现白å—,Grid组件ä¸ä¹Ÿå¯é€šè¿‡cachedCount属性设置GridItemçš„é¢„åŠ è½½æ•°é‡ï¼Œåªåœ¨æ‡’åŠ è½½LazyForEachä¸ç”Ÿæ•ˆã€‚ è®¾ç½®é¢„åŠ è½½æ•°é‡åŽï¼Œä¼šåœ¨Grid显示区域å‰åŽå„缓å˜cachedCount\*列数个GridItem,超出显示和缓å˜èŒƒå›´çš„GridItem会被释放。 ```ts Grid() { LazyForEach(this.dataSource, () => { GridItem() { } }) } .cachedCount(3) ``` >**说明:** > >cachedCountçš„å¢žåŠ ä¼šå¢žå¤§UIçš„CPUã€å†…å˜å¼€é”€ã€‚使用时需è¦æ ¹æ®å®žé™…情况,综åˆæ€§èƒ½å’Œç”¨æˆ·ä½“验进行调整。 ## 相关实例 é’ˆå¯¹ç½‘æ ¼å¼€å‘,有以下相关实例å¯ä¾›å‚考: - [游æˆ2048(ArkTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/Solutions/Game/Game2048) - [分布å¼è®¡ç®—器](https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/ArkTSDistributedCalc) <!--RP1--><!--RP1End-->