筆記:Develop in Swift Data Collections_Compositional Layout

沒想到collectionView這麼的有動態感XD
· 學習目標
· 基礎概念
· 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來設定元素的寬度。
在這個例子中,無論是寬度還是高度,都使用了fractionalWidth(0.25)。這意味著這個元素的寬度和高度都會是其容器寬度的25%,從而形成一個正方形。

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:
新增兩個作為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加入並在適當的位置顯示。
indexPath(for 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:) 
根據當前的布局,使用相應的「重用標識符」來獲取對應的單元格。

測試

GitHub

--

--

wei Tsao 學習紀錄
彼得潘的 Swift iOS / Flutter App 開發教室

Hi ! 我是wei , 先前未接觸過程式開發設計,想藉此來記錄自己的學習歷程,以利培養自己的程式邏輯 :)