SwiftUI 教學:利用 LazyVGrid 和 LazyHGrid 簡單步驟創建集合​​視圖


SwiftUI 最初的版本沒有原生集合​​視圖 (collection view)。你可以自己構建一個解決方案,或是使用第三方程式庫。在今年的 WWDC 中,Apple 為 SwiftUI 框架引入了許多新功能,其中一個就是實作 Grid 視圖。SwiftUI 現在為開發者提供兩個新的 UI 組件: LazyVGridLazyHGrid,一個用於創建垂直 Grid,另一種用於創建水平 Grid。正如 Apple 所說,“Lazy” 一詞意思是 Grid 視圖在需要時才會創建項目。

在這篇教學中,我會教你如何創建水平和垂直視圖。LazyVGridLazyHGrid 都設計得十分靈活,因此開發者可以輕鬆創建各種類型的 Grid 佈局。我們還會深入了解如何更改 Grid 項目的大小,以實現不同的佈局。

SwiftUI Grid 佈局的基礎

我們可以依照以下步驟,創建水平或垂直的 Grid 佈局:

  1. 準備要顯示在 Grid 中的原始數據。例如,以下是我們將在範例 App 中顯示的一組 SF Symbol:
   private var symbols = ["keyboard", "hifispeaker.fill", "printer.fill", "tv.fill", "desktopcomputer", "headphones", "tv.music.note", "mic", "plus.bubble", "video"]
  1. 創建一個 GridItem 陣列,來描述 Grid 的外觀。比如說,Grid 需要有多少列?以下是描述一個 3 列 (column) Grid 的範例程式碼:
   private var threeColumnGrid = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]
  1. 使用 LazyVGridScrollView 佈局 Grid。可以參考以下這是範例程式碼:
  ScrollView {
      LazyVGrid(columns: threeColumnGrid) {
          // Display the item
      }
  }
  1. 如果你想要構建水平 Grid,就如此使用 LazyHGrid
   ScrollView(.horizontal) {
       LazyHGrid(rows: threeColumnGrid) {
           // Display the item
       }
   }

使用 LazyVGrid 來創建垂直 Grid

對 Grid 佈局有一些基本了解之後,讓我們開始編寫程式碼吧!安裝了 Xcode 12 beta 後,使用新的 App 模板創建一個新專案。

Xcode 12 New Project Template

ContentView.swift 內,宣告以下變數 (variable):

private var symbols = ["keyboard", "hifispeaker.fill", "printer.fill", "tv.fill", "desktopcomputer", "headphones", "tv.music.note", "mic", "plus.bubble", "video"]

private var colors: [Color] = [.yellow, .purple, .green]

private var gridItemLayout = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]

我們將要在一個 3 列 Grid中顯示一組 SF Symbol。如此更新 body 變數來顯示 Grid:

var body: some View {
    ScrollView {
        LazyVGrid(columns: gridItemLayout, spacing: 20) {
            ForEach((0...9999), id: \.self) {
                Image(systemName: symbols[$0 % symbols.count])
                    .font(.system(size: 30))
                    .frame(width: 50, height: 50)
                    .background(colors[$0 % colors.count])
                    .cornerRadius(10)
            }
        }
    }
}

我們使用 LazyVGrid,並告訴垂直 Grid 使用 3 列佈局。我們還指定行與行之間有 20 point 的間距。在程式碼中,我們有一個 ForEach 迴圈 (loop),來顯示總共 10,000 個圖像視圖。如果有正確地跟隨步驟,你就會在預覽中看到一個三列 Grid。

swiftui-lazyvgrid-flexible

我們成功創建了一個三列的垂直 Grid 了!現在,圖像框架 (frame) 的大小固定為 50 x 50 point。你可以如此更改框架修飾符 (modifier):

.frame(minWidth: 0, maxWidth: .infinity, minHeight: 50)

然後,圖像的寬度就會擴大到列的寬度。

swiftui-lazyvgrid-three-column

利用 GridItem 更改 Grid 佈局 (Flexible/ Fixed/ Adaptive)

讓我們進一步看看 GridItem。你可以使用 GridItem 實例在 LazyHGridLazyVGrid 視圖中配置項目的佈局。在前文中,我們定義了一個有三個 GridItem 實例的陣列,而每個實例都使用尺寸型別 (Size Type) .flexible()。Flexible 尺寸型別讓我們可以創建三個大小相等的列。如果想要一個 6 列的 Grid,則可以如此創建 GridItem 陣列:

private var sixColumnGrid: [GridItem] = Array(repeating: .init(.flexible()), count: 6)

.flexible() 只是其中一個用於控制 Grid 佈局的尺寸型別。如果要在一行中放置盡可能多的項目,你可以使用如下的 adaptive 尺寸型別:

private var gridItemLayout = [GridItem(.adaptive(minimum: 50))]

Adaptive 尺寸型別要求你指定項目的最小尺寸 (minimum size)。在上面的程式碼中,我們設定了每個 Grid 項目的最小尺寸為 50。如果你像這樣修改 gridItemLayout 變數,就可以達到以下的 Grid 佈局:

lazyvgrid-swiftui-adaptive

我們使用了 .adaptive(minimum: 50),指示 LazyVGrid 在一行中填滿盡可能多的圖像,而每個項目的最小尺寸為 50 point。

除了 .flexible.adaptive 之外,如果想創建固定寬度的列,我們可以使用 .fixed。例如,我們想將圖像分為兩列,第一列的寬度為 100 point,第二列的寬度為 150 point,我們可以這樣編寫程式碼:

private var gridItemLayout = [GridItem(.fixed(100)), GridItem(.fixed(150))]

同樣地,如果你像這樣更新 gridItemLayout 變數,就會出現尺寸不同的兩列 Grid。

lazyvgrid-swiftui-fixed

你可以混合使用不同的尺寸型別,來創建更複雜的 Grid 佈局。例如,您可以定義一個 .fixedGridItem,然後定義一個 .adaptive 的GridItem,像這樣:

private var gridItemLayout = [GridItem(.fixed(150)), GridItem(.adaptive(minimum: 50))]

在這個情況下,LazyVGrid 將創建一個固定尺寸的列,其寬度為 100 point。然後,它會讓盡可能多的項目填滿剩餘空間。

lazyvgrid-swiftui-adaptive-fixed

使用 LazyHGrid 來創建水平 Grid

現在,您已經創建了垂直 Grid,LazyHGrid 可以很容易地將垂直 Grid 轉換為水平 Grid。水平 Grid 的用法與 LazyVGrid 幾乎完全相同,只是我們會將其嵌入到水平滾動視圖中。此外,LazyHGrid 的參數是 rows 而不是 columns

因此,我們只需要重寫幾行程式碼,就可以將 Grid 視圖從垂直方向轉換為水平方向:

ScrollView(.horizontal) {
    LazyHGrid(rows: gridItemLayout, spacing: 20) {
        ForEach((0...9999), id: \.self) {
            Image(systemName: symbols[$0 % symbols.count])
                .font(.system(size: 30))
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 50, maxHeight: .infinity)
                .background(colors[$0 % colors.count])
                .cornerRadius(10)
        }
    }
}

在預覽中執行範例或在模擬器上進行測試,你應該會看到一個水平 Grid。最棒的是,此 Grid 視圖可以自動支援 iPhone 和 iPad。

lazyhgrid-swiftui-fixed-adaptive-ipad

總結

SwiftUI 第一個版本中缺少的集合視圖現在已經推出了。SwiftUI 中的 LazyVGridLazyHGrid 讓開發者只需要幾行程式碼,就可以創建不同類型的 Grid 佈局。這篇教學只是簡單介紹了這兩個新 UI 組件,希望大家試試 GridItem 的不同配置,看看你可以實作出怎麼樣的 Grid 佈局吧!

編者備註如果你想深入了解SwiftUI 這個框架,可以參考我們的 《精通 SwiftUI》電子書。我們正在為新版本的 SwiftUI 更新電子書,購買後你可以免費得到更新的內容!

譯者簡介:Kelly Chan-AppCoda 編輯小姐。
原文:Building Collection Views in SwiftUI with LazyVGrid and LazyHGrid


軟件工程師,AppCoda 創辦人。著有《iOS 13 App 程式設計實力超進化實戰攻略》、《iOS 13 App 程式設計實力超進化實戰攻略》以及《精通 SwiftUI》。曾任職於HSBC, FedEx等公司,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda,致力於iOS程式教學,產品設計及開發。

blog comments powered by Disqus
Shares
Share This