筆記:Develop in Swift Data Collections_Compositional Layout
Published in
19 min readNov 17, 2023
· 學習目標
· 基礎概念
· 1.Compositional Layout Components
∘ 1–1.額外補充:不侷限於寬度或高度
· 2.Supplementary and Decoration Views
· 3.Multiple Layouts
· Lab - Emoji Dictionary (Part 3)
∘ 1.Review Starter Project
∘ 2.Create Grid Layout
∘ 3.Add Headers and Sections
∘ 4.Create Column Layout
∘ 5.Transition Between Layouts
∘ 測試
∘ GitHub
學習目標
- 組合式布局
(Compositional Layout)
是用在集合視圖(collection view)
的一種設計方法,可以自由組合不同的元素來創造出多樣化的界面。 - 它像樂高一樣,讓我們用小塊組件拼湊出大型的布局,適用於各種需要展示大量資料的介面。
- 項目(Items)、群組(Groups)、和區段(Sections)的協同工作
1. 項目 Item (NSCollectionLayoutItem) :
- 單個元素的布局,如一個圖片或一段文字。
2. 群組 Group (NSCollectionLayoutGroup) :
- 由多個項目組成,可以是水平的、垂直的或其他形式。
3. 區段 Section (NSCollectionLayoutSection) :
- 由一個或多個群組組成,是整個集合視圖的一部分。
- 使用補充視圖
(Supplementary Views)
「補充視圖」允許我們在「集合視圖」中添加更豐富的設計層次:
- EX: 標頭(headers)和頁腳(footers)。
- 它們增強數據的展示,讓顯示的內容不單調。
基礎概念
- Absolute Size
Absolute Size 就是在設計App界面時,給元素設定一個固定的尺寸,比如說寬50點、高100點。
特點
- 固定不變:無論在什麼手機或平板上,這個尺寸都不會變。
- 直接指定尺寸:設計時可以直接決定元素的大小。
- Decoration
NSCollectionLayoutDecorationItem 是用來給集合視圖的某個部分加背景的功能。
特點
- 美化:讓集合視圖的某部分更好看。
- 突出:幫助用戶區分不同區域。
- Estimated Size
在組合式布局中,Estimated Size 指的是一個大概的尺寸設定,不是確切的數值。
這種尺寸設定在內容真正顯示時才會確定最終大小。
特點:
- 提供彈性:當不確定元素的實際大小時,Estimated Size 讓開發者可以先設一個範圍。
- 自動調整:元素的最終尺寸會根據內容自動調整,適合變化多端的內容。
- Fractional size
組合式布局中,Fractional size」指的是以容器(如group)的高度或寬度的一部分來計算的尺寸。
它是用百分比來表示,而不是固定的數值。
特點:
- 靈活適應:它讓元素的大小能根據其「所在容器」的大小動態變化,適應不同的螢幕和佈局。
- 統一協調:在布局中可以保持元素間比例一致,使介面看起來更協調。
- Supplementary Item
像是在商品上加上促銷標籤,或者為相片加上時間標籤。這樣的細節可提升使用者的體驗和獲得更多資訊。
概念: 就像在集合視圖中的項目加上「標籤」或「裝飾邊框」。
功能: 讓集合視圖的每個項目更有特色,比如加上徽章或框架。
類別: 主要用 NSCollectionLayoutSupplementaryItem 來實現,
它的子類 NSCollectionLayoutBoundarySupplementaryItem 則用於處理邊緣裝飾。
1.Compositional Layout Components
- 在設計集合視圖時,不直接繼承
UICollectionViewLayout
,而是要用UICollectionViewCompositionalLayout
來實作,這是UICollectionViewLayout
的一種特殊形式。
- 佈局組成分為三部分:
區段(Sections)
、群組(Groups)
和項目(Items)
。
從小的單一項目開始,組合成群組,再將這些群組組織成一個完整的區段。
1.項目(Item)
- 基本概念: 就像一個方塊或一塊板塊,可以是任何一個元素,比如一張圖片或一段文字。
- 作用: 是組合式布局中的基石,每個項目代表一塊內容。
2.群組(Group)
- 簡單來說: 把好幾個項目放在一起,像是一排書架上的書籍。
- 特點: 可以是直的也可以是橫的,幫助把相關的項目整理在一起。
3.區段(Section)
- 基本定義: 大的分類,比如一個書店裡的「小說區」或「科學區」。
- 功能: 把一群群組集合起來,形成一個大的部分,每個區段都有自己的風格和內容。
NSCollectionLayoutSize
: 用於描述項目和群組的寬度和高度。
絕對值(absolute): 固定大小。
估計值(estimated): 根據渲染內容計算大小。
比例高度(fractionalHeight): 高度為容器高度的一部分。
比例寬度(fractionalWidth): 寬度為容器寬度的一部分。
- 綜合應用
組件組合: 這三種組件互相組合,形成整體的佈局。
尺寸選擇: 可以選擇「固定的尺寸」、「估計的尺寸」或者是基於容器大小的「比例尺寸」。
1–1.額外補充:不侷限於寬度或高度
不侷限於寬度或高度:
雖然名稱中有「Width」和「Height」,但它們並不僅限於設定寬度或高度。
可以用fractionalWidth來設定元素的高度,也可以用fractionalHeight來設定元素的寬度。
2.Supplementary and Decoration Views
- 輔助視圖
(Supplementary Views)
:
1. 主要用來加強視覺效果,像是加上「標籤」或「裝飾性文字」。
2. 使用 NSCollectionLayoutSupplementaryItem 來創建單一項目或群組的額外視覺元素。
3. NSCollectionLayoutBoundarySupplementaryItem 則用於製作固定在區段上方或下方的元素,比如標題或頁尾。
- 裝飾視圖
(Decoration Views)
:
NSCollectionLayoutDecorationItem:用於為一個區段提供背景視圖。
- 特性和用法
1. 這些都是NSCollectionLayoutItem的子類別,所以它們繼承了所有的基本特性。
2. 這些特殊的視圖種類具有獨特的屬性,讓它們有別於一般的項目。
3. 這些視圖是獨立於用來顯示資料的單元格的。
所以標題或頁尾這種輔助視圖不應該直接依賴於區段中的每個項目。
- 使用和配置
1. 這些視圖與用於顯示數據的單元格是分開的。
EX: 一個區段的標題或頁尾不應直接依賴於該區段中顯示的單個項目。
2. 像常規的單元格一樣,需要用重用標識(reuse identifier)來註冊這些視圖,
然後依需要將它們取出(dequeue)。
3. 把這些特殊視圖分配給適當的屬性後,系統就會自動處理它們的顯示和排列。
- 屬性賦值簡介
1. NSCollectionLayoutSupplementaryItems分配給
- NSCollectionLayoutItem 或 NSCollectionLayoutGroup 的 supplementaryItems。
2. NSCollectionLayoutBoundarySupplementaryItems 分配給
- NSCollectionLayoutSection 或 UICollectionViewCompositionalLayout 的 boundarySupplementaryItems。
3. NSCollectionLayoutDecorationItems分配給
- NSCollectionLayoutSection 的 decorationItems。
3.Multiple Layouts
- 在開發 App 時,使用
UICollectionViewCompositionalLayout
來實現複雜的集合視圖布局(CollectionView Layouts)
。 - 可以在 App 中定義多個
組合式布局
,甚至可以在同一個集合視圖之間進行切換。 - 這種做法主要是通過:
使用 UICollectionView 的 setCollectionViewLayout(_:animated:) 或
setCollectionViewLayout(_:animated:completion:) 來實現。
- 範例:
集合視圖的布局被更改為generateNewLayout()所返回的布局,
並且此變化過程會以動畫的形式呈現,讓使用者可以看到介面是如何變化的。
Lab — Emoji Dictionary (Part 3)
- 網格和欄式佈局:
專案將會包括兩種顯示方式:
1. 一種是網格佈局(grid layout),另一種是欄式佈局(columnar layout)。
2. 網格佈局通常是多個小單元格排列成的網格,而欄式佈局則是像報紙那樣,資訊呈現在不同的欄位中。
- 加入標題:
在不同部分加入簡單的標題((section headers)),幫助使用者更好地瀏覽和分辨內容。
1.Review Starter Project
- Main.storyboard:
Main.storyboard:
1. 有兩種原型單元格,一種「標準網格排版」,另一種用於「欄式排版」。
2. 它們有不同的reuseIdentifier,但都使用相同的類別 EmojiCollectionViewCell。
3. 這是因為兩種單元格之間的輸出都是相同的;唯一的區別在於它們的方向。
- EmojiCollectionViewHeader
用程式碼設置視圖,這個可重複使用的視圖被設計為類似於「表格視圖」中的「標題區」的外觀。
2.Create Grid Layout
- 建立網格佈局:
1. 設定間距:
- 定義CGFloat型別的變數padding,值設為20,用來確保周圍的間距一致。
2. 配置布局項目:
- 建立一個NSCollectionLayoutItem,尺寸設定為容器的100%。
3. 建立水平布局群組:
- 創建一個橫向的NSCollectionLayoutGroup,寬度是容器的100%,高度是四分之一,
內含2個剛剛設定的項目,形成每行兩格的網格。
4. 設定群組的間距與內邊距:
- 為這個群組加上間距和內邊距,以保持清晰度並分隔單元格。
5. 建立集合佈局部分:
- 用這個群組創建一個NSCollectionLayoutSection,設置群組間的間距,並調整上下的內邊距。
6. 返回組合佈局:
- 回傳一個基於這個新部分的UICollectionViewCompositionalLayout。
- 在
viewDidLoad()
中應用佈局:
建立一個 UICollectionViewLayout? 名為layout,然後在viewDidLoad()中設置並應用此佈局。
3.Add Headers and Sections
- 這些
Sections
會根據表情符號名稱的首字母
進行分隔,並按字母順序展示。 - 設定Header Id:
- 建立
Section 結構體
、新增sectionTitle
計算屬性:
1. 建立 Section 結構體
- 增加 Section 結構,遵循 Codable 協議。
- 兩個屬性:一個是存儲標題(String)的 title,另一個是存儲 Emoji 陣列的 emojis。
2. 新增 sectionTitle 計算屬性
- 在 Emoji 中,新增 sectionTitle 計算屬性。
- 此屬性將 Emoji 名稱轉為大寫,並取其首字母作為分區標題。
- 若首字母不存在,則使用「?」代替。
- 註冊Header視圖:
在 viewDidLoad() ,註冊Header視圖為集合視圖的「輔助視圖」。
使用 collectionView.register 方法,指定標頭視圖的類型、種類和識別碼。
一個輔助視圖是用「withReuseIdentifier」和「forSupplementaryViewOfKind」來註冊的。
這個「forSupplementaryViewOfKind」是一個用來指示其用途的字符串。
輔助視圖不僅限於Header和Footer。
- 初始化分區陣列、更新分區方法:
1. 初始化分區陣列:
- 在 EmojiCollectionViewController 中,新增 sections 的陣列,類型為 Section。
2. 更新分區方法:
- 新增 updateSections 方法來更新分區。
- 首先清空 sections 陣列。
- 根據 sectionTitle 將 emojis 陣列分組,並對每組進行排序。
- 將排序後的結果加入 sections 陣列。
##
透過Dictionary(grouping:by:)構造函數,
以emoji的「分區標題」作為鍵(key),相應的「emoji陣列」作為值(value),創建一個新的字典。
這裡的「分區標題」是從emoji的名稱的首字母計算得來的。
##
- 實現集合視圖的
「數據源方法」
:
修改numberOfSections(in:)的返回值為sections的數量。
修改collectionView(_:numberOfItemsInSection:)的返回值為某一分類中emoji的數量。
- 處理emoji的新增與編輯:
1. 新增indexPath(for emoji: Emoji)方法,用來找出特定emoji在集合視圖中的位置。
2. 在 unwindToEmojiTableView(segue:) 中,根據選中的情況來判斷是更新還是新增emoji。
- 如果是更新,就替換原有的emoji並重載該項目
- 如果是新增,則將新emoji加入並在適當的位置顯示。
- 刪除表情符號(Emoji):
1. 首先,使用indexPath找到要刪除的emoji。
2. 檢查這個emoji在主數據源(emojis)中的索引。如果找不到,則不進行後續操作。
3. 在兩個數據源(emojis和sections)中移除這個emoji。
4. 最後,在集合視圖中刪除這個項目。
- 刪除動作的特殊處理:
1. 刪除操作需要單獨修改數據源陣列,而不是像修改操作後呼叫updateSections()那樣。
2. 直接修改數據源,避免在「更新區段」時造成集合視圖佈局的混亂。
- 設置 Section Headers:
collectionView(_:viewForSupplementaryElementOfKind:at:)
方法中,配置並返回一個重用的Header視圖,設置為該區段的標題。
- 產生Header布局:
1. 這個方法創建一個NSCollectionLayoutBoundarySupplementaryItem:
- 配置為容器寬度的100%,高度為40點。
2. 設置類型為headerKind,將這個邊界項目對齊到容器頂部。
3. 設置pinToVisibleBounds為true,使Header在集合視圖中固定在頂部。
- 在生成網格布局
(generateGridLayout())
中加入Header
:
在方法的末尾添加一行代碼,將「生成的Header」作為「邊界補充項目」加入到「每個區段」。
4.Create Column Layout
- 設定 Column Layout
(generateColumnLayout)
1. 設定邊界間距(Padding):
- 首先,設置 padding,值為10,用來表示元件之間的空間。
2. 創建布局項目(Item):
- 建立一個布局項目,高度和寬度都是容器的100%。
3. 定義水平排列的群組(Group):
- 創建一個水平排列的群組,寬度是容器的100%,高度設為120點。
- 這個群組包含剛剛建立的布局項目。
4. 為群組設定邊界:
- 群組的前後(左右)邊界設定為 padding 的值。
5. 建立布局的區塊(Section):
- 利用剛剛建立的群組來創建一個新的布局區塊。
- 設定區塊之間的間隔為 padding,並為區塊的頂部和底部設定 padding 邊界。
6. 加入頂部視圖:
- 使用 generateHeader() 方法回傳的值,設定區塊的邊界補充項目。
7. 返回最終布局:
- 最後,返回一個新的 UICollectionViewCompositionalLayout,以這個區塊作為配置。
5.Transition Between Layouts
- 準備
切換布局
:
新增一個 Layout 的 Enum,它有兩種情況:grid(網格)和 column(列)。
- 建立
布局字典
:
將原本的布局(layout)改為一個字典。
鍵(key)是 Layout 列舉的值,而值(value)則是 UICollectionViewLayout。
- 設置
預設布局、更新機制、更新按鈕圖示
:
1. 在 viewDidLoad() 裡,設定 grid 和 column 的對應布局。
- 增加一個 activeLayout 變數來記錄目前使用的布局。
- 當這個變數改變時,會自動更新視圖,包括「重載項目」和「切換布局動畫」。
2. 轉換完畢後,更新導航欄的圖標以反映新的布局。
- 實現布局切換按鈕功能:
在 switchLayouts(sender:) 方法中,依據目前的 activeLayout,切換到另一種布局。
- 處理集合視圖的
重用標識符
:
collectionView(_:cellForItemAt:)
根據當前的布局,使用相應的「重用標識符」來獲取對應的單元格。