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

2024-01-25 13:13 更新

概述

網(wǎng)格布局是由“行”和“列”分割的單元格所組成,通過指定“項(xiàng)目”所在的單元格做出各種各樣的布局。網(wǎng)格布局具有較強(qiáng)的頁面均分能力,子組件占比控制能力,是一種重要自適應(yī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)每一個條目對應(yīng)一個GridItem組件,如下圖所示。

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

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

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

圖2 網(wǎng)格布局

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

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

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

設(shè)置排列方式

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

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

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

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

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

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

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

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

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

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

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

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

圖5 計(jì)算器

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

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

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

“=”按鍵橫跨第五行和第六行,只要將將“=”對應(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è)置行列數(shù)量與占比,可以通過layoutDirection可以設(shè)置網(wǎng)格布局的主軸方向,決定子組件的排列方式。此時可以結(jié)合minCount和maxCount屬性來約束主軸方向上的網(wǎng)格數(shù)量。

圖6 主軸方向示意圖

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

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

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

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

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

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

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

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

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

  1. Grid() {
  2. GridItem() {
  3. Text('會議')
  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')

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

  1. @Component
  2. struct OfficeService {
  3. @State services: Array<string> = ['會議', '投票', '簽到', '打印']
  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è)置行列間距

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

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

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

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

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

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

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

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

如上圖所示的橫向可滾動網(wǎng)格布局,只要設(shè)置rowsTemplate屬性的值且不設(shè)置columnsTemplate屬性,當(dāng)內(nèi)容超出Grid組件寬度時,Grid可橫向滾動進(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ū)域時,可水平滾動。
  16. .rowsGap(15)
  17. ...
  18. }
  19. ...
  20. }
  21. }

控制滾動位置

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

圖10 日歷翻頁

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

  1. private scroller: Scroller = new Scroller()

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

  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('上一頁')
  9. .onClick(() => {
  10. this.scroller.scrollPage({
  11. next: false
  12. })
  13. })
  14. Button('下一頁')
  15. .onClick(() => {
  16. this.scroller.scrollPage({
  17. next: true
  18. })
  19. })
  20. }
  21. }
  22. ...

性能優(yōu)化

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

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

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

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

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

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號