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

2024-01-25 13:13 更新

概述

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

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

布局與約束

Grid組件為網格容器,其中容器內每一個條目對應一個GridItem組件,如下圖所示。

圖1 Grid與GridItem組件關系
說明

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

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

圖2 網格布局

如果Grid組件設置了寬高屬性,則其尺寸為設置值。如果沒有設置寬高屬性,Grid組件的尺寸默認適應其父組件的尺寸。

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

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

設置排列方式

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

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

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

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

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

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

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

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

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

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

圖4 不均勻網格布局

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

圖5 計算器

在單個網格單元中,rowStart和rowEnd屬性表示指定當前元素起始行號和終點行號,columnStart和columnEnd屬性表示指定當前元素的起始列號和終點列號。

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

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

“=”按鍵橫跨第五行和第六行,只要將將“=”對應GridItem的的rowStart和rowEnd設為5和6即可。

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

設置主軸方向

使用Grid構建網格布局時,若沒有設置行列數(shù)量與占比,可以通過layoutDirection可以設置網格布局的主軸方向,決定子組件的排列方式。此時可以結合minCount和maxCount屬性來約束主軸方向上的網格數(shù)量。

圖6 主軸方向示意圖

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

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

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

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

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

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

網格布局采用二維布局的方式組織其內部元素,如下圖所示。

圖7 通用辦公服務

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')

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

  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. }

設置行列間距

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

圖8 網格的行列間距

通過Grid的rowsGap和columnsGap可以設置網格布局的行列間距。在圖5所示的計算器中,行間距為15vp,列間距為10vp。

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

構建可滾動的網格布局

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

圖9 橫向可滾動網格布局

如果設置的是columnsTemplate,Grid的滾動方向為垂直方向;如果設置的是rowsTemplate,Grid的滾動方向為水平方向。

如上圖所示的橫向可滾動網格布局,只要設置rowsTemplate屬性的值且不設置columnsTemplate屬性,當內容超出Grid組件寬度時,Grid可橫向滾動進行內容展示。

  1. @Component
  2. struct Shopping {
  3. @State services: Array<string> = ['直播', '進口', ...]
  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') // 只設置rowsTemplate屬性,當內容超出Grid區(qū)域時,可水平滾動。
  16. .rowsGap(15)
  17. ...
  18. }
  19. ...
  20. }
  21. }

控制滾動位置

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

圖10 日歷翻頁

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

  1. private scroller: Scroller = new Scroller()

在日歷頁面中,用戶在點擊“下一頁”按鈕時,應用響應點擊事件,通過指定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ù)量較小的布局場景,當構建具有大量網格項的可滾動網格布局時,推薦使用數(shù)據(jù)懶加載方式實現(xiàn)按需迭代加載數(shù)據(jù),從而提升列表性能。

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

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

設置預加載數(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、內存開銷。使用時需要根據(jù)實際情況,綜合性能和用戶體驗進行調整。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號