使用SwiftUI Grid實現Bento Grid UI,提升資訊組織與視覺美感

閱讀時間約 17 分鐘

自從我開始從事APP設計開發以來,每年我都會關注Apple的WWDC。這個系列活動會介紹針對不同操作系統的最新軟體與科技。自WWDC20起,Apple將一個主題的所有重點整合在一個畫面中呈現。內容以圓角矩形卡片的形式展現,每張卡片傳達一個特點,卡片大小會根據資訊內容或權重進行調整,並基於網格系統進行動態有序的排版。下圖便是今年WWDC24中關於iOS18最新資訊的介紹。

raw-image

這種Apple慣於用於宣傳新產品特點的排版手法,便是自2023年起流行的Bento Grid設計,中文稱為”便當盒設計“。


Table of contents

  • Bento Grid
  • SwiftUI Grid
  • SwiftUI Bento Grid
  • Conclusion


Bento Grid

Bento Grid的起源

raw-image

如其名稱所示,Bento Grid 的靈感來自日本便當(弁当,bento)盒的分格方式。其特色在於以四方結構為間隔,提供多種菜餚在有限空間內各自擁有獨立的放置區域。這不僅提升了菜餚的承裝數量,也使食用者能一覽所有菜色;在進食過程中,也能方便且優雅地夾取食物。

日本便當展現了實用性與簡潔優雅的設計,體現出純淨的美感,是機能與美感兼具的經典設計範例。這種以使用者(食用者)的角度出發,考量產品整體使用過程(從承裝到食用的體驗)的設計理念,正是「形隨機能」(Form Follows Function)的體現。


Bento Grid 的特點

將便當盒的分隔手法轉化到介面設計上,可以將頁面分隔成大小不一的方塊,以呈現不同的內容。這種設計方式對設計師和使用者都具有以下優點:

模組化與彈性佈局(High Modularity and Flexibility)

  • Bento Grid 中的每個方塊(或稱模組)都可以自由調整大小、形狀和位置,為設計師提供了一個既有規則又不受限制的佈局框架。
  • 當設計師需要在一個畫面上呈現大量資訊時,格狀卡片佈局有助於清晰劃分資訊,並根據內容的重要性和視覺層級靈活調整方塊的大小與排列。

視覺層次與引導(Clear Visual Hierarchy and Guidance)

  • 井然有序的模組化佈局使使用者能快速掃描頁面,找到所需資訊。
  • 透過方塊的大小、位置和顏色的運用,能有效引導使用者的視線至重要內容,形成清晰的視覺層級。
  • 透過方塊排列方式的規劃,可以將相關內容歸類在一起,設計出清晰的視覺路徑,引導使用者的視線流動。


Bento Grid 的設計原則

讓我們以設計師實事求是的精神來檢視Apple WWDC24產品特點總覽的畫面設計,看看它是否遵循了Grid佈局原則。在這裡,我使用Figma的Layout grid進行比對。新增一個Frame元件,並設置畫面尺寸為1194 x 670。接著,在Layout grid中分別新增Columns和Rows:

  • Columns:將Count設置為20,Margin(邊界)和Gutter(分欄間距)各設置為10。
  • Rows:將Count設置為12,Margin(邊界)和Gutter(分欄間距)各設置為10。

同樣地,當你在設計Bento Grid時,可以善用Layout grid來作為網格佈局的參考。

Figma Grid Layout

Figma Grid Layout

可以確定的是,WWDC24產品頁面中的網格完全遵循了Layout grid的系統,並根據資訊內容的層級進行了大小不一的變化。


SwiftUI Grid

SwiftUI 的 Grid 是一種佈局容器,類似於文書工具中常見的表格,可以輕鬆地將內容組織成行(Rows)和列(Columns)。Grid 由三個主要構成元素組成,以下是其關鍵概念的說明:

  1. GridGrid 可以根據螢幕尺寸動態調整內容佈局,自動調整行與列的排列,以適應各種設備和狀況。其中,alignment 參數用於設定列(Columns)的對齊位置;horizontalSpacingverticalSpacing 參數則相當於分欄間距的概念。
  2. GridRowGridRow 用於管理單行中的所有列內容,並可通過新增 GridRow 來增加行(Rows)的數量。
  3. Column:在SwiftUI中無需特別定義Column,因為每個容器(如TextImageShape)本身就充當一個Column。
Grid(alignment: .center, horizontalSpacing: gutter, verticalSpacing: gutter) {
    GridRow {
        Text("Row 1 / Column 1")
        Text("Row 1 / Column 2")
    }
    GridRow {
        Text("Row 2 / Column 1")
        Text("Row 2 / Column 2")
    }
}
SwiftUI Grid

SwiftUI Grid


Grid配置

當然,SwiftUI 提供了一些網格修飾符,可以讓我們設計出更具彈性和進階功能的表格。以下是兩個我實際使用過的配置功能:

gridCellColumn:使用 .gridCellColumns(_:) 修飾符可以讓某個網格橫跨多列,實現類似於 Word 中的跨欄或 Google Doc 中的合併儲存格效果。

GridRow {
    Text("Row 1 / Column 1")
        .padding()
        .background(Color.gray, in: RoundedRectangle(cornerRadius: 10))
        .gridCellColumns(2)
}

gridCellColumns(2) 內的參數2代表著"Column 1"橫跨2個欄位,加上 "Column 2"佔據1個Column,整個GridRow則創造了3個Column。這個概念對於稍後要實現的Bento Grid是關鍵的配置功能。

SwiftUI Grid gridCellColumn

SwiftUI Grid gridCellColumn


gridCellUnsizedAxes:如果需要將網格的高度或寬度設置為無限大,以填滿整個欄位空間,可以使用 gridCellUnsizedAxes(_:) 修飾符來指定網格的適當大小。否則,網格可能會無限延伸,佔據整個屏幕。

GridRow {
    Text("Row 1 / Column 1")
        .padding()
        .frame(maxWidth: .infinity)
        .gridCellUnsizedAxes(.horizontal)
        .background(Color.gray, in: RoundedRectangle(cornerRadius: 10))
        .gridCellColumns(2)
}

對於 "Row 1 / Column 1",使用了 .frame(maxWidth: .infinity) 並搭配 gridCellUnsizedAxes(.horizontal),以指定其寬度必須根據內容適當調整。這樣,網格只會填滿2個欄位的寬度,而不會無限延伸。

SwiftUI Grid gridCellUnsizedAxes

SwiftUI Grid gridCellUnsizedAxes


SwiftUI Bento Grid

接下來,我將展示如何使用SwiftUI Grid來實現Bento Grid。我們將以Apple WWDC24的Bento Grid佈局作為參考,並給每個網格區塊分配一個英文編號以便識別。

WWDC Bento Grid

WWDC Bento Grid


局部佈局

為了容易理解,讓我們先實作Grid B 到Grid F的局部佈局。

Grid(alignment: .leading, horizontalSpacing: gutter, verticalSpacing: gutter) {
    //GridRow that contains GridCard B&C and GridCard D
    GridRow {
        VStack(spacing: gutter) {
            GridCard("B")
                .frame(height: cellSize?.height)
            GridCard("C")
                .frame(height: cellSize?.height)
        }
        .gridCellColumns(6)

        GridCard("D")
            .gridCellColumns(4)
            .frame(height: gridCellRows(4))
    }

    //GridRow that contains GridCard E and GridCard F
    GridRow {
        GridCard("E")
            .gridCellColumns(2)
            .readSize { value in
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
                    //Use PreferenceKey to read the basic grid width
                    cellSize = CGSize(width: value.width, height: value.width)
                }
            }
  

        GridCard("F")
            .gridCellColumns(8)
    }
    .frame(height: gridCellRows(4))
}
  1. 建立Grid容器:設置 horizontalSpacingverticalSpacing,這些間距參數等於gutter的概念。
  2. 建立第一個GridRow:此列包含2個欄位,分別是GridCard B與C的堆疊和GridCard D。GridCard B與C的堆疊欄寬佔據整體Layout的6個網格,設置 .gridCellColumns(6)。GridCard D的欄寬佔據整體Layout的4個網格,設置 .gridCellColumns(4);列高佔據4個網格,設置 .frame(height: gridCellRows(4))
  3. 建立第二個GridRow:此列的列高也佔據4個網格,設置 .frame(height: gridCellRows(4));包含2個欄位,分別是GridCard E和GridCard F。GridCard E佔據2個網格,設置 .gridCellColumns(2)。GridCard F佔據8個網格,設置 .gridCellColumns(8)
raw-image
善用 gridCellColumns 修飾符可以定義網格單元在Grid容器中所佔的欄位數量,讓我們自由地調整網格的欄寬。



整體佈局

有了基本的Grid概念後,就讓我們接著完成整個Grid佈局。

Grid(alignment: .center, horizontalSpacing: gutter, verticalSpacing: gutter) {
    //GridRow that contains Grid AL and Grid AL
    GridRow {
        //Grid AL that contains GridRow AF and GridRow MR
        Grid(alignment: .leading, horizontalSpacing: gutter, verticalSpacing: gutter) {
            //GridRow AF that contains GridCard A and GridBF B2F
            GridRow {
                GridCard("A")
                    .gridCellColumns(4)
                    .frame(height: gridCellRows(8))

                GridBF()
                    .gridCellColumns(10)
            }

            //GridRow GL that contains GridCard G2L
            GridRow {
                GridCardGL()
            }
            .frame(height: gridCellRows(4))
        }

        .gridCellColumns(14)

        //Grid MR that contains GridCard M2R
        Grid(alignment: .leading, horizontalSpacing: gutter, verticalSpacing: gutter) {
            GridCardMR()
        }

        .frame(height: gridCellRows(12))
        .gridCellColumns(6)
    }
}
.frame(height: gridCellRows(12))
  1. 建立Grid容器:設置 horizontalSpacingverticalSpacing,這些間距參數等於gutter的概念。
  2. 建立第一個GridRow:此列包含兩個Grid,分別是Grid AL和Grid MR。
  3. Grid AL:內部包含兩個GridRow。第一個GridRow 包含GridCard A 和先前建立的GridBF中的GridRow AF。第二個GridRow 包含GridRow GL。
  4. Grid MR:由四個GridRow組成。基於先前展示的Step 1 - Grid B2F的概念,實現起來會相對容易,這裡不再詳述。

因此,通過靈活運用Grid和GridRow的變化組合,我們可以成功還原Apple WWDC24 Bento Grid的佈局!

SwiftUI Bento Grid

SwiftUI Bento Grid

GridRow 中可以包含多個 Grid,而 Grid 又可以包含多個 GridRow,就像俄羅斯娃娃一樣。掌握了這個概念,我們就能輕鬆實現複雜的Grid佈局。


最後,我將前面仿照WWDC24的Bento Grid套用到oThings的產品特色與功能說明中。結果證明,Bento Grid的佈局方式確實方便設計師規劃內容豐富的界面。透過網格的尺寸變化與配置,能夠提供規律、彈性以及具視覺層次的資訊呈現。這是一種由理性編排支撐的感性視覺美感。

oThings Bento Grid

oThings Bento Grid

附帶一提,中間oThings logo卡片的漸層背景使用了iOS18推出的MeshGradient漸層功能,這是一個非常強大的漸層效果。通過以下程式碼,你可以定義網格的格數、座標與顏色參數,輕鬆設計出優美的漸層視覺效果。

MeshGradient(width: 2, height: 2, points: [
    [0, 0], [1, 0], [0, 1], [1, 1]
], colors: [
    .cyan, .yellow, .green, .purple
])



oThings是Kyle獨立設計與開發的APP, 是一款專為您的生活記憶而設的記憶保存應用程式,讓您專注於記錄珍愛的事物。以SwiftUI介面框架開發,結合設計的創意與程式的創新所創造的混合體驗設計,呈現高質感的動畫轉場與絲滑的互動效果,打造具品牌辨識度的使用體驗。歡迎有興趣的您下載體驗。


Conclusion

透過這次使用SwiftUI Grid實踐Bento Grid的實驗,我深刻體會到SwiftUI Grid的功能雖然簡單,但卻非常強大。以下是幾點關於Bento Grid的心得:

  1. 適合大尺寸屏幕:大尺寸畫面,例如平板或電腦較大的螢幕,能夠容納更多的網格,從而突顯出網格間的變化差異。
  2. 善用Grid與GridRow的組合:雖然GridRow需要被Grid包覆,但內層也可以再包覆Grid,這樣才能創造出複雜的Grid佈局。當處理全新的複雜佈局時,可以先通過簡單的繪圖拆解GridGridRow的結構關係,這樣會更容易進行畫面的設計。
  3. Grid的欄位數量由Grid內定義:與Word或Google Doc中的表格功能不同,SwiftUI Grid的網格欄位數量是由Grid自身定義的。例如,在一個GridRow內放置兩個視圖,對於Grid而言,整體欄位數量為2。當我們對某個欄位定義了 .gridCellColumns(3),那麼整體的欄位數量就會增加到4個。



2會員
4內容數
在這瞬息萬變的世界中,讓設計師們以混合成長思維的視角思考自身的職涯規劃,以混合體驗設計的觀點思考使用者體驗設計。
留言0
查看全部
發表第一個留言支持創作者!
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
這篇文章探討瞭如何在iOS應用程式中客製化Alert,包括改變字體大小、內嵌連結以及讓Alert的高度隨著字數增長並提供scroll操作。同時使用SwiftUI進行客製化,並介紹瞭解決高度超出範圍後文字捲動與scrollView固定高度的方法。
Thumbnail
PROCESS macro for SPSS 可以用非常簡單方式學會調節中介模式。本文將介紹四種類型的變項,並解釋調節式中介的公式,還有如何操作最4.0版本的PROCESS macro for SPSS。文末也會附上所有所有Process模型圖例,提供給讀者方便分析~
Thumbnail
PROCESS macro for SPSS 可以用非常簡單方式使用調節分析。本文將介紹三種類型的變項,還有如何操作最4.2版本的PROCESS macro for SPSS進行調節模式。文末也會附上所有所有Process模型圖例,提供給讀者方便分析~
Thumbnail
PROCESS macro for SPSS 可以用非常簡單方式進中介模式。本文將介紹三種類型的變項,還有如何操作最4.0版本的PROCESS macro for SPSS。文末也會附上所有所有Process模型圖例,提供給讀者方便分析~
Thumbnail
Potato Media雖然和方格子及Matters同樣歸類為寫作平台,同樣強調將內容變現,前者卻與後面兩者完全不同,當然,所獲得的收入報酬也不會一樣,更清楚一點來說,連獲得收益的方式也大不相同。
Thumbnail
我們將介紹各種類型的信度和統計方法,包含Cohen Kappa 係數、組內相關係數、α係數的SPSS教學。信度的可以使用不同的評估方法來評估。信度對於確定評分標準或量表的一致性和穩定度至關重要。
Thumbnail
如果依變項並非連續變項時,就可以改用羅吉斯迴歸。接下來本文將介紹勝算、勝算比、計算範例、二元/順序/多項式羅吉斯迴歸分析範例和SPSS操作方法。
Thumbnail
通常我們對於類別變項就直接看敘述統計大小,但如果我們想要用檢定確定兩者差距是達到統計顯著,就要用卡方檢定(Chi-square test)是一種統計學方法,獨立性考驗用於檢驗兩個類別變項各組別之間是否有顯著關聯。本文將介紹卡方檢定並介紹上機操作和事後比較方法。
Thumbnail
本篇介紹Mplus的「結構方程模型(Structural Equation Modelling, SEM)」之語法內容,並透過例題向大家示範如何分析撰寫SEM的語法。本文為新手教學,輸入方式可能不是最有效率,但是比較簡單且不太會犯錯
Thumbnail
當樣本有所關聯時,就不能使用獨立樣本t檢定,而是需要使用相依樣本t檢定,本文檢定介紹使用時機,並教導如何使用SPSS進行相依樣本t檢定
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
這篇文章探討瞭如何在iOS應用程式中客製化Alert,包括改變字體大小、內嵌連結以及讓Alert的高度隨著字數增長並提供scroll操作。同時使用SwiftUI進行客製化,並介紹瞭解決高度超出範圍後文字捲動與scrollView固定高度的方法。
Thumbnail
PROCESS macro for SPSS 可以用非常簡單方式學會調節中介模式。本文將介紹四種類型的變項,並解釋調節式中介的公式,還有如何操作最4.0版本的PROCESS macro for SPSS。文末也會附上所有所有Process模型圖例,提供給讀者方便分析~
Thumbnail
PROCESS macro for SPSS 可以用非常簡單方式使用調節分析。本文將介紹三種類型的變項,還有如何操作最4.2版本的PROCESS macro for SPSS進行調節模式。文末也會附上所有所有Process模型圖例,提供給讀者方便分析~
Thumbnail
PROCESS macro for SPSS 可以用非常簡單方式進中介模式。本文將介紹三種類型的變項,還有如何操作最4.0版本的PROCESS macro for SPSS。文末也會附上所有所有Process模型圖例,提供給讀者方便分析~
Thumbnail
Potato Media雖然和方格子及Matters同樣歸類為寫作平台,同樣強調將內容變現,前者卻與後面兩者完全不同,當然,所獲得的收入報酬也不會一樣,更清楚一點來說,連獲得收益的方式也大不相同。
Thumbnail
我們將介紹各種類型的信度和統計方法,包含Cohen Kappa 係數、組內相關係數、α係數的SPSS教學。信度的可以使用不同的評估方法來評估。信度對於確定評分標準或量表的一致性和穩定度至關重要。
Thumbnail
如果依變項並非連續變項時,就可以改用羅吉斯迴歸。接下來本文將介紹勝算、勝算比、計算範例、二元/順序/多項式羅吉斯迴歸分析範例和SPSS操作方法。
Thumbnail
通常我們對於類別變項就直接看敘述統計大小,但如果我們想要用檢定確定兩者差距是達到統計顯著,就要用卡方檢定(Chi-square test)是一種統計學方法,獨立性考驗用於檢驗兩個類別變項各組別之間是否有顯著關聯。本文將介紹卡方檢定並介紹上機操作和事後比較方法。
Thumbnail
本篇介紹Mplus的「結構方程模型(Structural Equation Modelling, SEM)」之語法內容,並透過例題向大家示範如何分析撰寫SEM的語法。本文為新手教學,輸入方式可能不是最有效率,但是比較簡單且不太會犯錯
Thumbnail
當樣本有所關聯時,就不能使用獨立樣本t檢定,而是需要使用相依樣本t檢定,本文檢定介紹使用時機,並教導如何使用SPSS進行相依樣本t檢定