創(chuàng)建網(wǎng)格(Grid/GridItem)

2024-01-25 13:13 更新

概述

網(wǎng)格布局是由“行”和“列”分割的單元格所組成,通過(guò)指定“項(xiàng)目”所在的單元格做出各種各樣的布局。網(wǎng)格布局具有較強(qiáng)的頁(yè)面均分能力,子組件占比控制能力,是一種重要自適應(yīng)布局,其使用場(chǎng)景有九宮格圖片展示、日歷、計(jì)算器等。

ArkUI提供了Grid容器組件和子組件GridItem,用于構(gòu)建網(wǎng)格布局。Grid用于設(shè)置網(wǎng)格布局相關(guān)參數(shù),GridItem定義子組件相關(guān)特征。Grid組件支持使用條件渲染、循環(huán)渲染、懶加載等渲染控制方式生成子組件。

布局與約束

Grid組件為網(wǎng)格容器,其中容器內(nèi)每一個(gè)條目對(duì)應(yīng)一個(gè)GridItem組件,如下圖所示。

圖1 Grid與GridItem組件關(guān)系
說(shuō)明

Grid的子組件必須是GridItem組件。

網(wǎng)格布局是一種二維布局。Grid組件支持自定義行列數(shù)和每行每列尺寸占比、設(shè)置子組件橫跨幾行或者幾列,同時(shí)提供了垂直和水平布局能力。當(dāng)網(wǎng)格容器組件尺寸發(fā)生變化時(shí),所有子組件以及間距會(huì)等比例調(diào)整,從而實(shí)現(xiàn)網(wǎng)格布局的自適應(yīng)能力。根據(jù)Grid的這些布局能力,可以構(gòu)建出不同樣式的網(wǎng)格布局,如下圖所示。

圖2 網(wǎng)格布局

如果Grid組件設(shè)置了寬高屬性,則其尺寸為設(shè)置值。如果沒(méi)有設(shè)置寬高屬性,Grid組件的尺寸默認(rèn)適應(yīng)其父組件的尺寸。

Grid組件根據(jù)行列數(shù)量與占比屬性的設(shè)置,可以分為三種布局情況:

  • 行、列數(shù)量與占比同時(shí)設(shè)置:Grid只展示固定行列數(shù)的元素,其余元素不展示,且Grid不可滾動(dòng)。(推薦使用該種布局方式)
  • 只設(shè)置行、列數(shù)量與占比中的一個(gè):元素按照設(shè)置的方向進(jìn)行排布,超出的元素可通過(guò)滾動(dòng)的方式展示。
  • 行列數(shù)量與占比都不設(shè)置:元素在布局方向上排布,其行列數(shù)由布局方向、單個(gè)網(wǎng)格的寬高等多個(gè)屬性共同決定。超出行列容納范圍的元素不展示,且Grid不可滾動(dòng)。

設(shè)置排列方式

設(shè)置行列數(shù)量與占比

通過(guò)設(shè)置行列數(shù)量與尺寸占比可以確定網(wǎng)格布局的整體排列方式。Grid組件提供了rowsTemplate和columnsTemplate屬性用于設(shè)置網(wǎng)格布局行列數(shù)量與尺寸占比。

rowsTemplate和columnsTemplate屬性值是一個(gè)由多個(gè)空格和'數(shù)字+fr'間隔拼接的字符串,fr的個(gè)數(shù)即網(wǎng)格布局的行或列數(shù),fr前面的數(shù)值大小,用于計(jì)算該行或列在網(wǎng)格布局寬度上的占比,最終決定該行或列的寬度。

圖3 行列數(shù)量占比示例

如上圖所示,構(gòu)建的是一個(gè)三行三列的的網(wǎng)格布局,其在垂直方向上分為三等份,每行占一份;在水平方向上分為四等份,第一列占一份,第二列占兩份,第三列占一份。

只要將rowsTemplate的值為'1fr 1fr 1fr',同時(shí)將columnsTemplate的值為'1fr 2fr 1fr',即可實(shí)現(xiàn)上述網(wǎng)格布局。

  1. Grid() {
  2. ...
  3. }
  4. .rowsTemplate('1fr 1fr 1fr')
  5. .columnsTemplate('1fr 2fr 1fr')
說(shuō)明

當(dāng)Grid組件設(shè)置了rowsTemplate或columnsTemplate時(shí),Grid的layoutDirection、maxCount、minCount、cellLength屬性不生效,屬性說(shuō)明可參考Grid-屬性。

設(shè)置子組件所占行列數(shù)

除了大小相同的等比例網(wǎng)格布局,由不同大小的網(wǎng)格組成不均勻分布的網(wǎng)格布局場(chǎng)景在實(shí)際應(yīng)用中十分常見(jiàn),如下圖所示。在Grid組件中,通過(guò)設(shè)置GridItem的rowStart、rowEnd、columnStart和columnEnd可以實(shí)現(xiàn)如圖所示的單個(gè)網(wǎng)格橫跨多行或多列的場(chǎng)景。

圖4 不均勻網(wǎng)格布局

例如計(jì)算器的按鍵布局就是常見(jiàn)的不均勻網(wǎng)格布局場(chǎng)景。如下圖,計(jì)算器中的按鍵“0”和“=”,按鍵“0”橫跨第一、二兩列,按鍵“=”橫跨第五、六兩行。使用Grid構(gòu)建的網(wǎng)格布局,其行列標(biāo)號(hào)從1開(kāi)始,依次編號(hào)。

圖5 計(jì)算器

在單個(gè)網(wǎng)格單元中,rowStart和rowEnd屬性表示指定當(dāng)前元素起始行號(hào)和終點(diǎn)行號(hào),columnStart和columnEnd屬性表示指定當(dāng)前元素的起始列號(hào)和終點(diǎn)列號(hào)。

所以“0”按鍵橫跨第一列和第二列,只要將“0”對(duì)應(yīng)GridItem的columnStart和columnEnd設(shè)為1和2,將“=”對(duì)應(yīng)GridItem的的rowStart和rowEnd設(shè)為5和6即可。

  1. GridItem() {
  2. Text(key)
  3. ...
  4. }
  5. .columnStart(1)
  6. .columnEnd(2)

“=”按鍵橫跨第五行和第六行,只要將將“=”對(duì)應(yīng)GridItem的的rowStart和rowEnd設(shè)為5和6即可。

  1. GridItem() {
  2. Text(key)
  3. ...
  4. }
  5. .rowStart(5)
  6. .rowEnd(6)

設(shè)置主軸方向

使用Grid構(gòu)建網(wǎng)格布局時(shí),若沒(méi)有設(shè)置行列數(shù)量與占比,可以通過(guò)layoutDirection可以設(shè)置網(wǎng)格布局的主軸方向,決定子組件的排列方式。此時(shí)可以結(jié)合minCount和maxCount屬性來(lái)約束主軸方向上的網(wǎng)格數(shù)量。

圖6 主軸方向示意圖

當(dāng)前l(fā)ayoutDirection設(shè)置為Row時(shí),先從左到右排列,排滿(mǎn)一行再排一下一行。當(dāng)前l(fā)ayoutDirection設(shè)置為Column時(shí),先從上到下排列,排滿(mǎn)一列再排一下一列,如上圖所示。此時(shí),將maxCount屬性設(shè)為3,表示主軸方向上最大顯示的網(wǎng)格單元數(shù)量為3。

  1. Grid() {
  2. ...
  3. }
  4. .maxCount(3)
  5. .layoutDirection(GridDirection.Row)
說(shuō)明

1. layoutDirection屬性?xún)H在不設(shè)置rowsTemplate和columnsTemplate時(shí)生效,此時(shí)元素在layoutDirection方向上排列。

2. 僅設(shè)置rowsTemplate時(shí),Grid主軸為水平方向,交叉軸為垂直方向。

2. 僅設(shè)置columnsTemplate時(shí),Grid主軸為垂直方向,交叉軸為水平方向。

在網(wǎng)格布局中顯示數(shù)據(jù)

網(wǎng)格布局采用二維布局的方式組織其內(nèi)部元素,如下圖所示。

圖7 通用辦公服務(wù)

Grid組件可以通過(guò)二維布局的方式顯示一組GridItem子組件。

  1. Grid() {
  2. GridItem() {
  3. Text('會(huì)議')
  4. ...
  5. }
  6. GridItem() {
  7. Text('簽到')
  8. ...
  9. }
  10. GridItem() {
  11. Text('投票')
  12. ...
  13. }
  14. GridItem() {
  15. Text('打印')
  16. ...
  17. }
  18. }
  19. .rowsTemplate('1fr 1fr')
  20. .columnsTemplate('1fr 1fr')

對(duì)于內(nèi)容結(jié)構(gòu)相似的多個(gè)GridItem,通常更推薦使用循環(huán)渲染ForEach語(yǔ)句中嵌套GridItem的形式,來(lái)減少重復(fù)代碼。

  1. @Component
  2. struct OfficeService {
  3. @State services: Array<string> = ['會(huì)議', '投票', '簽到', '打印']
  4. ...
  5. build() {
  6. Column() {
  7. Grid() {
  8. ForEach(this.services, service => {
  9. GridItem() {
  10. Text(service)
  11. ...
  12. }
  13. }, service => service)
  14. }
  15. .rowsTemplate('1fr 1fr')
  16. .columnsTemplate('1fr 1fr')
  17. ...
  18. }
  19. ...
  20. }
  21. }

設(shè)置行列間距

在兩個(gè)網(wǎng)格單元之間的網(wǎng)格橫向間距稱(chēng)為行間距,網(wǎng)格縱向間距稱(chēng)為列間距,如下圖所示。

圖8 網(wǎng)格的行列間距

通過(guò)Grid的rowsGap和columnsGap可以設(shè)置網(wǎng)格布局的行列間距。在圖5所示的計(jì)算器中,行間距為15vp,列間距為10vp。

  1. Grid() {
  2. ...
  3. }
  4. .columnsGap(10)
  5. .rowsGap(15)

構(gòu)建可滾動(dòng)的網(wǎng)格布局

可滾動(dòng)的網(wǎng)格布局常用在文件管理、購(gòu)物或視頻列表等頁(yè)面中,如下圖所示。在設(shè)置Grid的行列數(shù)量與占比時(shí),如果僅設(shè)置行、列數(shù)量與占比中的一個(gè),即僅設(shè)置rowsTemplate或僅設(shè)置columnsTemplate屬性,網(wǎng)格單元按照設(shè)置的方向排列,超出Grid顯示區(qū)域后,Grid擁有可滾動(dòng)能力。

圖9 橫向可滾動(dòng)網(wǎng)格布局

如果設(shè)置的是columnsTemplate,Grid的滾動(dòng)方向?yàn)榇怪狈较?;如果設(shè)置的是rowsTemplate,Grid的滾動(dòng)方向?yàn)樗椒较颉?/p>

如上圖所示的橫向可滾動(dòng)網(wǎng)格布局,只要設(shè)置rowsTemplate屬性的值且不設(shè)置columnsTemplate屬性,當(dāng)內(nèi)容超出Grid組件寬度時(shí),Grid可橫向滾動(dòng)進(jìn)行內(nèi)容展示。

  1. @Component
  2. struct Shopping {
  3. @State services: Array<string> = ['直播', '進(jìn)口', ...]
  4. ...
  5. build() {
  6. Column({ space: 5 }) {
  7. Grid() {
  8. ForEach(this.services, (service: string, index) => {
  9. GridItem() {
  10. ...
  11. }
  12. .width('25%')
  13. }, service => service)
  14. }
  15. .rowsTemplate('1fr 1fr') // 只設(shè)置rowsTemplate屬性,當(dāng)內(nèi)容超出Grid區(qū)域時(shí),可水平滾動(dòng)。
  16. .rowsGap(15)
  17. ...
  18. }
  19. ...
  20. }
  21. }

控制滾動(dòng)位置

與新聞列表的返回頂部場(chǎng)景類(lèi)似,控制滾動(dòng)位置功能在網(wǎng)格布局中也很常用,例如下圖所示日歷的翻頁(yè)功能。

圖10 日歷翻頁(yè)

Grid組件初始化時(shí),可以綁定一個(gè)Scroller對(duì)象,用于進(jìn)行滾動(dòng)控制,例如通過(guò)Scroller對(duì)象的scrollPage方法進(jìn)行翻頁(yè)。

  1. private scroller: Scroller = new Scroller()

在日歷頁(yè)面中,用戶(hù)在點(diǎn)擊“下一頁(yè)”按鈕時(shí),應(yīng)用響應(yīng)點(diǎn)擊事件,通過(guò)指定scrollPage方法的參數(shù)next為true,滾動(dòng)到下一頁(yè)。

  1. Column({ space: 5 }) {
  2. Grid(this.scroller) {
  3. ...
  4. }
  5. .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
  6. ...
  7. Row({space: 20}) {
  8. Button('上一頁(yè)')
  9. .onClick(() => {
  10. this.scroller.scrollPage({
  11. next: false
  12. })
  13. })
  14. Button('下一頁(yè)')
  15. .onClick(() => {
  16. this.scroller.scrollPage({
  17. next: true
  18. })
  19. })
  20. }
  21. }
  22. ...

性能優(yōu)化

長(zhǎng)列表的處理類(lèi)似,循環(huán)渲染適用于數(shù)據(jù)量較小的布局場(chǎng)景,當(dāng)構(gòu)建具有大量網(wǎng)格項(xiàng)的可滾動(dòng)網(wǎng)格布局時(shí),推薦使用數(shù)據(jù)懶加載方式實(shí)現(xiàn)按需迭代加載數(shù)據(jù),從而提升列表性能。

關(guān)于按需加載優(yōu)化的具體實(shí)現(xiàn)可參考數(shù)據(jù)懶加載章節(jié)中的示例。

當(dāng)使用懶加載方式渲染網(wǎng)格時(shí),為了更好的滾動(dòng)體驗(yàn),減少滑動(dòng)時(shí)出現(xiàn)白塊,Grid組件中也可通過(guò)cachedCount屬性設(shè)置GridItem的預(yù)加載數(shù)量,只在懶加載LazyForEach中生效。

設(shè)置預(yù)加載數(shù)量后,會(huì)在Grid顯示區(qū)域前后各緩存cachedCount*列數(shù)個(gè)GridItem,超出顯示和緩存范圍的GridItem會(huì)被釋放。
  1. Grid() {
  2. LazyForEach(this.dataSource, item => {
  3. GridItem() {
  4. ...
  5. }
  6. })
  7. }
  8. .cachedCount(3)
說(shuō)明

cachedCount的增加會(huì)增大UI的CPU、內(nèi)存開(kāi)銷(xiāo)。使用時(shí)需要根據(jù)實(shí)際情況,綜合性能和用戶(hù)體驗(yàn)進(jìn)行調(diào)整。

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)