筆記:Develop in Swift Data Collections_Advanced Compositional Layouts
Published in
32 min readNov 21, 2023
· 學習目標
· 基礎概念
· 模仿 iOS App Store 首頁的布局
· 1.Promoted Section Layout
∘ 1–1.設定資料來源:
∘ 1–2.設定資料來源並配置單元格:
∘ 1–3.註冊自訂的集合視圖單元格:
∘ 1–4.設計「推廣區段」的佈局:
∘ 1–5.設定滾動行為:
∘ 補充 orthogonalScrollingBehavior:
· 2.Standard Section Layout
∘ 2–1.布局概念
∘ 2–2.實際設置部分
∘ 2–3.設定「資料來源快照」並「配置單元格」:
∘ 2–4.集合視圖註冊單元格
· 3.Categories Section Layout
∘ 3–1.布局設計
∘ 3–2.佈局實現
∘ 3–3.數據源和快照定義
∘ 3–4.Collection View 設置
∘ 3–5.動態計算 Item Insets
· 4.Supplementary Views
∘ 4–1.布局中使用的三種輔助視圖
∘ 4–2.註冊輔助視圖
· 5.Standard and Categories Section Headers
∘ 5–1.設定 Supplementary Views
∘ 5–2.定義「SectionHeaderView」的標題
∘ 5–3.將 Supplementary Views 加入布局
· 6.Separator Line Supplementary View
∘ 6–1.設計考量:
∘ 6–2.分隔線的設置:
∘ 6–3.最終的布局
∘ GitHub
· Lab - iTunes Search (Part 5)
∘ 目標
∘ 1.Adding All Search Scope
∘ 2.Making Multiple Requests
∘ 2–1.fetchMatchingItems 開始前清空快照,然後請求資料:
∘ 2–2.handleFetchedItems 處理回應的項目:
∘ 2–3.fetchAndHandleItemsForSearchScopes處理多任務並行(TaskGroup):
∘ 補充: checkCancellation() 和 CancellationError 的主要差異和應用場景
· 3.Sectioning Search Results
∘ 3–1.建立分區快照
∘ 3–2.使用分區快照(createSectionedSnapshot):
· 4.Table View Section Headers
∘ 4–1.建立子類別:
∘ 4–2.在視圖控制器中進行更新:
· 6.Collection View Section Headers
∘ 6–1.建立 Headers 視圖類別:
∘ 6–2.在集合視圖控制器中註冊標題視圖
∘ 6–3.配置集合視圖數據源以提供標題視圖
· 7.Collection View Layout
∘ 7–1.移除既有的排版程式碼、並新增排版設定方法
∘ 7–2.使用 UICollectionViewCompositionalLayout
∘ 7–3.調用新的排版設定方法
∘ 7–4.調整排版以適應不同的搜索範圍
∘ 7–5.更新排版設定
∘ 7–6.使用 SearchScope 擴展來簡化排版邏輯
∘ GitHub
學習目標
- 設置具有獨特布局的區段
(Sections)
:
為每個區段設計獨特的布局。
讓 App界面 更加豐富多彩,每個區段都有其特色。
- 設置組合式布局中「正交滾動」
(orthogonally scrolling)
的區段:
「正交滾動」指的是在主滾動方向(通常是垂直的)之外的滾動,如水平滾動。
這樣可以在同一螢幕上展示更多內容,而用戶可以透過不同方向滾動來瀏覽。
基礎概念
- 錨點
(Anchor)
是一種布局工具,用來指定怎麼把一個額外的元素(比如標籤或圖標)固定在集合視圖的某個項目上。
使用要點
- 附加元素固定:
EX: 如果有個顯示產品的集合視圖,可能會想在某個產品旁邊添加價格標籤。
錨點就是用來把這標籤「固定」在產品旁的工具。
- 自由布局:
EX: 利用錨點,可以自由地在項目周圍添加額外資訊,並且可以精確控制這些資訊的位置,
像是項目的上方、下方或側邊。
- layout environment
它是一組關於「界面布局」所處情境。這包括了視圖的大小、內容邊距,以及其他環境特性。
使用要點
- 獲取情境資訊:
EX: 當設計一個可變(diffable)數據源的布局時,布局環境提供所需的所有背景資訊。
- 適應不同條件:
EX: 可以根據容器的大小或設備的方向(橫或直)來調整布局。
- Orthogonal
在使用集合視圖(collection view)的組合布局(compositional layout)時,
用來描述一種特殊的滾動方式。
- 當一個集合視圖的區段(section)設定為「orthogonal」時,這個區段的滾動方向會和
視圖的主要滾動方向成「直角」。
- EX: 如果整個視圖主要是上下滾動的,那麼設為「orthogonal」的區段就會「左右滾動」。
模仿 iOS App Store 首頁的布局
- 使用
單一集合視圖
實現複雜布局:
這個布局是通過使用「單一集合視圖」和「具有不同區段的組合布局」來實現的。
- 重點是創建組合布局並加強對 UICollectionViewDiffableDataSource 的了解。
- 預設的項目和資料:
已經設定了一些基礎項目,包括用於模擬 App Store 清單的示例數據和預先設計的單元格。
- 這裡用隨機顏色代替圖片和 AppIcon,以便集中注意力在布局上。
1.Promoted Section Layout
1–1.設定資料來源:
首先建立 NSDiffableDataSourceSnapshot,並指定推廣區段(promoted)和
相對應的項目(Item.promotedApps)。
- 使用 appendSections 和 appendItems 方法來將區段和項目加入快照(Snapshot)中。
- 設定Snapshot前,將 sections 屬性設為Snapshot的 sectionIdentifiers。
- dataSource.apply(snapshot) 用於將快照應用到數據源。
1–2.設定資料來源並配置單元格:
在 configureDataSource() ,初始化數據源並設定「cellProvider」。
- 根據索引路徑(IndexPath)的區段,來決定返回的cell類型。
- 對於推廣區段(.promoted),返回一個配置過的 PromotedAppCollectionViewCell。
1–3.註冊自訂的集合視圖單元格:
註冊自訂單元格是為了讓集合視圖知道如何創建和管理這些單元格,並允許開發者自訂這些單元格的外觀
和行為,同時還利用了集合視圖的cell重用機制來提升App的效能。
- 註冊 PromotedAppCollectionViewCell。
- 使用 collectionView.register 方法來進行註冊。
1–4.設計「推廣區段」的佈局:
1. 設計「推廣區段」的佈局
- 創建一個 UICollectionViewCompositionalLayout。
- 根據區段創建佈局,對於推廣區段(.promoted),設計一個接近螢幕寬度的group,正方形的比例。
2. 調整項目間距:
- 使用 contentInsets 屬性來為項目添加間隔,在項目初始化後加入前後間距。
1–5.設定滾動行為:
- 為了讓「推廣項目」橫向滾動,使用 orthogonalScrollingBehavior 來設定區段的滾動方式。
- 使用.groupPagingCentered 來實現類似 App Store 的滾動效果,使群組在滾動停止後居中顯示。
補充 orthogonalScrollingBehavior:
1. 主軸方向:
- 集合視圖裡的分區,一般都是按照主軸(就是設定的滾動方向)來排列內容。
- 主軸可以是直的(垂直)或橫的(水平),由 scrollDirection 屬性決定。
2. 改變分區滾動:
- 要改變某個分區的滾動模式,就調整它的 orthogonalScrollingBehavior 屬性。
- 預設的 UICollectionLayoutSectionOrthogonalScrollingBehavior.none 表示跟隨主軸滾動。
3. 設定橫向滾動:
- 把 orthogonalScrollingBehavior 改成其他值後,分區就會橫向於主軸滾動。(正交)
- 比方說,如果主軸是直的,設定後分區就會變成橫向滾動。
2.Standard Section Layout
- 後面會使用
supplementary view
來添加區塊名稱
。 - 此外每個群組的第三個項目下方沒有分隔線。
2–1.布局概念
1. 區塊滾動:
- 整個區塊是「正交滾動」的,並且使用 groupPagingCentered 行為。
2. 群組設計:
- 每個群組包含三個垂直排列的項目。這些群組的寬度與推廣項目相同,但稍微矮一點。
3. 項目大小:
- 每個項目佔據其所在群組的100%寬度和三分之一的高度。
2–2.實際設置部分
1. 在建立布局時,可以從小項目開始設計,一步步往上到整個區塊;也可以反過來。
2. 要創建群組,可以使用NSCollectionLayoutGroup.vertical。
3. 在createLayout()裡面,加入一個設定.standard區塊的部分增加一個案例。
4. 為了使界面更加美觀,為項目增加「內邊距」。
2–3.設定「資料來源快照」並「配置單元格」:
1. 在「資料來源快照」中加入.standard區塊並應用到資料源。
2. 實作資料來源的cellProvider閉包,處理.standard案例。
## 注意到在「每個群組」的「第三個項目」下方沒有分隔線。##
2–4.集合視圖註冊單元格
3.Categories Section Layout
3–1.布局設計
1. 不滾動的 Section:
- 這個區塊不會像其他區塊那樣水平或垂直滾動。
2. 單一項目的群組:
- 每個群組只包含一個項目。群組的寬度佔據整個區塊的寬度,高度則類似於標準表格視圖行的高度。
3. 項目佔滿群組:
- 每個項目都佔滿其所在的群組。
3–2.佈局實現
1. 使用NSCollectionLayoutSize和NSCollectionLayoutItem來設定 item 大小和樣式。
2. 設定 group 的大小,使其寬度為 section 的 100%,高度估計為 44(像標準行高)。
3. 最後,將 item 放入 vertical group 中,再將此 group 放入 section。
3–3.數據源和快照定義
1. 更新數據源和快照以包含新的分類 section。
2. 為每個 section 添加相應的 items,使用 NSDiffableDataSourceSnapshot 管理這些數據。
3–4.Collection View 設置
1. 註冊並返回 cell(CategoryCollectionViewCell)。
2. 為 categories section 的 item 更新配置方法 configureCell(:hideBottomLine:),
並根據是否是最後一個 item 來決定是否隱藏底線。
3–5.動態計算 Item Insets
1. 為了讓 categories items 與上方的 group 對齊,需要動態計算它們的 insets。
2. 使用「layoutEnvironment」的訊息計算需要的 inset 值,確保在不同設備尺寸上都能正確顯示。
4.Supplementary Views
- 在
UICollectionView
中,除了主要的內容顯示,還有一些額外的元件可以用來增強或補充內容,這些就叫做輔助視圖
。它們常用於顯示如標題、分隔線等。
4–1.布局中使用的三種輔助視圖
頭部視圖(Header):用來放置標籤和按鈕。
頂部線條(Top Line):展示一條分隔線。
底部線條(Bottom Line):也是用來展示分隔線。
4–2.註冊輔助視圖
1. 「註冊輔助視圖」的方式和「註冊單元格(cell)」類似。
2. 需要一個繼承自 UICollectionReusableView 的視圖、一個重用標識符(reuse identifier)
和一個種類(kind)。
5.Standard and Categories Section Headers
5–1.設定 Supplementary Views
1. 在 configureDataSource() 中,設定 dataSource.supplementaryViewProvider,
這樣就能告訴 Collection View 怎麼建立和設定 Supplementary Views。
2. 使用 switch 來分別處理不同類型的Supplementary Views。
- SectionHeaderView 和 LineView
5–2.定義「SectionHeaderView」的標題
1. 用 Section Enum 來決定顯示哪種標題(例如categories標題或standard標題)。
2. 根據 Collection View 當前的區段(section),設定「標題視圖」的「標題文字」。
- 將 setTitle() 中的 "TODO" 替換為 sectionName。
- 這樣布局(layout)就能將這些補充視圖放置在它認為合適的地方,而
supplementaryViewProvider 閉包將提供它們。
5–3.將 Supplementary Views 加入布局
1. 透過 NSCollectionLayoutBoundarySupplementaryItem 建立一個「標題項目」,
並把它跟 Collection View 的邊緣連結起來。
2. 設置標題視圖的尺寸和邊距,讓它跟整體布局風格協調。
3. 在 Collection View 的布局設定裡,把這個「標題項目」加到「相對應的分區」裡。
- 說明
1. 使用 NSCollectionLayoutBoundarySupplementaryItem:
- 這個元素會被anchor到 NSCollectionLayoutSection 的邊界,根據 NSRectAlignment
這種對齊屬性定位,包括像是 .top、.topLeading 和 .topTrailing。
2. 對齊標題:
- 選擇 .top 對齊來放置標題。在 UI 中,「標題視圖」的邊緣會與「群組」的邊緣對齊,
呈現居中並有一些前後間距。
- 這個對齊設定會讓布局自動居中標題,省去了手動計算居中所需的複雜計算。
3. 設定Supplementary Views大小和間距:
- 補充項目使用 NSCollectionLayoutSize 定義,與一般項目和群組相似,
但有額外的 contentInsets 屬性。
- 標題的大小設定為寬度的 92%,高度約 44 點,並且在前後各有 4 點的內容間距。
4. 實作標題項目:
- 在 UICollectionViewCompositionalLayout 的 sectionProvider 閉包中,
使用 NSCollectionLayoutBoundarySupplementaryItem(layoutSize:elementKind:alignment:)
創建 headerItem。
- 然後,將 headerItem 及其屬性定義好後,添加到節的 boundarySupplementaryItems 屬性中,這個屬性接收 NSCollectionLayoutBoundarySupplementaryItem 的數組。
- 補充:Category 部分
由於前面在 switch 外面定義 headerItem,這樣就能在 .standard 和 .categories
兩種情況下都使用它。
6.Separator Line Supplementary View
- 分隔線的目的是在不同區塊間增加細微的分隔,提升設計感。
- 在
UICollectionViewCompositionalLayout
中,這些分隔線被稱作邊界補充項目(boundary supplementary items
)。
6–1.設計考量:
- 一開始可能認為每個區塊上方加一條線即可,但由於
邊界補充項目
的特性,這麼做會有問題(例如線可能會被標題視圖遮住)
。 不同類型的區塊
需要不同的邊界補充項目配置:
promoted section:上下都有分隔線。
standard section:有標題視圖和下方分隔線。
category section:只有標題視圖。
6–2.分隔線的設置:
1. 分隔線的寬度設為「群組」寬度的92%,並有前後間距(leading and trailing content insets)。
2. 分隔線的高度應等於螢幕上單個像素的物理大小,可以在運行時根據顯示器的比例(display scale)來確定。
3. 透過 UITraitCollection 協議來獲取 displayScale,進而計算分隔線的高度。
- 實踐
1. 定義分隔線項目的大小和位置,並設置內容間距。
2. 根據不同的區塊類型,將適當的邊界補充項目添加到區塊的boundarySupplementaryItems陣列中。
3, 為了達到良好的視覺效果,需要調整section.contentInsets。
6–3.最終的布局
- 檢查分隔線的位置和間距
Lab — iTunes Search (Part 5)
目標
1. 加入新搜索範圍:
- 在搜尋功能中新增「全部」,讓使用者能搜尋所有類型的內容。
2. 調整網路請求:
- 改變原有的網路請求設定,以支援新加入的「全部」搜尋範圍。
3. 設計集合視圖(Collection View)的佈局:
- 與表格視圖(Table View)不同,集合視圖沒有內建的 section 顯示方式,需要自己設計。
- 考慮集合視圖的特性,設計一個更實用、有創意的佈局。
4. 清楚分類展示結果:
- 按類型將搜尋結果分成不同區塊,方便識別。
1.Adding All Search Scope
- 建立
SearchScope
:
定義 SearchScope 的 Enum,包括「all」、「movies」、「music」、「apps」和「books」。
- Enum 的功能:
title:顯示「搜尋範圍」的名字。
mediaType:用於 API 查詢的「媒體類型」,例如電影是 "movie"。
- 更新
StoreItemContainerViewController
:
把原有使用 String 的地方改為使用 SearchScope Enum。
使用 map 設置 searchController 的 scopeButtonTitles。
- 修改
queryOptions
:
設置計算屬性 selectedSearchScope 來取得當前選擇的搜索範圍。(取代queryOptions)
## 這會導致 fetchMatchingItems() 方法出現錯誤。 ##
- 解決程式出錯問題:
1. query 內移除 mediaType ,改用 selectedSearchScope.mediaType。
2. 在 do/catch 中,用 query["media"] == selectedSearchScope.mediaType 替換原有的判斷條件。
- 測試 App
能看到新增的「All」範圍。
使用「All」進行搜索時,會看到不同類型的結果列表。
## 注意: ##
- 由於 iTunes 搜尋服務包含了超出四種媒體類型(如 Podcast),
而 API 不允許指定一個媒體類型列表(比如 "movies,music,books,apps"),
因此需要進行多個請求。
2.Making Multiple Requests
- 多重請求的需求
當用戶選擇「All」搜尋範圍時,需要分別對 Movies、Music、Apps和Books進行請求。
這可以通過在循環中多次調用正在使用的 fetchItems(matching:) 來實現。
- 處理非同步及無序的回應
每個請求將會「獨立」且以「不確定的順序」回傳,因此需要一種方法來收集這些結果,然後顯示它們。
可以使用 diffable snapshots 和 data sources。
- 修改itemsSnapshot的定義:
在 StoreItemContainerViewController 中,將 itemsSnapshot 的定義替換為:
var itemsSnapshot = NSDiffableDataSourceSnapshot<String, StoreItem>()。
2–1.fetchMatchingItems 開始前清空快照,然後請求資料:
1. 在 fetchMatchingItems() 開頭,先執行 itemsSnapshot.deleteAllItems() 清空快照,
再進行資料請求。
2. 附加的 catch 子句,用於捕獲並忽略任何 CancellationError。
這與現有的用於 URLSession 錯誤的子句功能類似(很快就會看到這些錯誤的來源)。
- 根據搜尋範圍發起請求:
1. 若搜尋範圍為「All」,則發送「四種類型」的請求。
2. 若非「All」,只發送「特定範圍」的請求。透過遍歷 SearchScopes 陣列來實現。
2–2.handleFetchedItems 處理回應的項目:
1. 當請求回傳項目時,加入到快照並更新資料來源。
2. 新增 handleFetchedItems(_ items: [StoreItem]) async 來執行這些動作。
- apply(_:animatingDifferences:) 是可等待的,所以將這個標記為異步的。
- 更新快照並顯示結果:
在 handleFetchedItems(_:) 中,將接收到的項目加入 itemsSnapshot,以整合每次回應的內容。
2–3.fetchAndHandleItemsForSearchScopes處理多任務並行(TaskGroup)
:
1. 使用 TaskGroup 管理多個並行任務。
2. 新增 fetchAndHandleItemsForSearchScopes(_:withSearchTerm:)
- 它是異步的且可能會拋出錯誤。
- 這個方法將在 fetchMatchingItems() 方法的 do/catch 中的 do 中被調用。
- 檢查與處理任務取消:
並行環境中,定期檢查任務是否被取消,並適時中斷。使用 try Task.checkCancellation() 來進行。
- 更新快照並顯示結果:
1. 對於每個結果,將首先檢查「當前的SearchTerm」是否仍然與「搜索欄中的字詞」匹配,
以及是否處於所選搜索範圍內。
2. 如果這兩個條件都成立,則調用 handleFetchedItems(_:) 方法來處理結果。
這種方法的好處是它允許更好地管理並行任務,並在適當的時候檢查取消。
- 測試
當使用 "All" 範圍進行搜索時。
結果列表會按「媒體類型」分組顯示。多次搜索可能會因網路請求而導致媒體類型顯示順序不同。
補充: checkCancellation()
和 CancellationError
的主要差異和應用場景
3.Sectioning Search Results
- 要在 App 中設計一個集合視圖,讓不同種類的搜尋結果分別顯示在不同的
區段
。每個項目會占用總寬度的三分之一,高度為166點。
- 利用
StoreItem
進行分類:
每個從網路服務取得的StoreItem都會有一個kind屬性。
這個屬性會指出該項目是哪種媒體類型,例如Movie、Music、App或Book。
3–1.建立分區快照
需要根據kind屬性將StoreItem分組,
然後建立一個NSDiffableDataSourceSnapshot<String, StoreItem>,
其中的分區要按照Movie、Music、App、Book的順序排列。
- 分區快照的建立過程:
1. 首先,根據kind值篩選出不同類型的媒體。
2. 然後,創建一個元組陣列,將篩選出來的數據與對應的搜尋範圍(SearchScope)配對。
3. 建立一個空的快照,並遍歷這些元組,將每個分區及其項目添加進快照中。
如果某個分區的項目數量為零,則不創建該分區。
3–2.使用分區快照(createSectionedSnapshot):
- 在處理從網路取得的項目時,使用
createSectionedSnapshot(from:)
,確保這些項目可以正確地顯示在列表和集合視圖中。
- 結果顯示的一致性:
遵循這些步驟,可以確保搜尋結果按照特定的順序顯示,但目前還不包含分區的標題顯示。
4.Table View Section Headers
- 基本概念:
在傳統的 UITableView 使用中,要顯示段落(Section)標題通常會實作
UITableViewDataSource 協議中的 tableView(_:titleForHeaderInSection:) ,
返回一個字串作為標題。
- 使用
UITableViewDiffableDataSource
的改變:
1. 當使用 UITableViewDiffableDataSource 來管理數據源時,這部分的責任就轉交給了該實例。
2. 要提供段落標題,需要建立 UITableViewDiffableDataSource 的子類別,
並重寫 tableView(_:titleForHeaderInSection:) 方法。
4–1.建立子類別:
建立 StoreItemTableViewDiffableDataSource。
它是 UITableViewDiffableDataSource 的一個具體子類別。
- 改寫方法以設定標題:
1. 覆寫 tableView(_:titleForHeaderInSection:) 方法。
2. 方法中,使用 snapshot().sectionIdentifiers[section] 來取得對應的段落標題。
4–2.在視圖控制器中進行更新:
1. 在 StoreItemContainerViewController 中,將 tableViewDataSource 屬性的類型
更新為 StoreItemTableViewDiffableDataSource。
2. 更新 configureTableViewDataSource(_:) 方法,使其調用新類別的初始化函數。
6.Collection View Section Headers
這個步驟主要是關於在集合視圖中創建和配置用於顯示段落標題的補充視圖。
- 標題視圖設計:
這個標題視圖的設計類似於表格視圖(Table View)的段落標題,包含一個背景顏色
和顯示段落標題的標籤。
- 視圖註冊:
在使用任何補充視圖(例如標題視圖)前,需要先在集合視圖中進行註冊。
- 視圖提供:
使用 supplementaryViewProvider 閉包來為每個段落提供相應的標題視圖,
這是集合視圖顯示補充視圖的標準流程。
6–1.建立 Headers 視圖類別:
1. 新建 StoreItemCollectionViewSectionHeader,繼承自 UICollectionReusableView。
2. 在這個類別裡,建立一個標籤(UILabel),用來顯示每個段落的標題。
6–2.在集合視圖控制器中註冊標題視圖
在 StoreItemCollectionViewController,使用 collectionView.register()
來註冊剛剛建立的 StoreItemCollectionViewSectionHeader 類別。
6–3.配置集合視圖數據源以提供標題視圖
1. 在 StoreItemContainerViewController 裡的 configureCollectionViewDataSource(_:)
,設定一個 supplementaryViewProvider。
2. 這個閉包會根據每個段落的索引、種類(kind),從重用池中取得並回傳一個配置好的標頭視圖。
7.Collection View Layout
- 目的:
讓每組結果成為一個獨立的區塊,並在水平方向上滾動(orthogonally scroll)。
- 尺寸設定:
每個項目(item)占據群組(group)寬度的三分之一,高度設定為固定的 166 點(points)。
7–1.移除既有的排版程式碼、並新增排版設定方法
- 在
StoreItemCollectionViewController
的viewDidLoad()
方法中移除所有已存在的排版相關程式碼。 - 增加一個新方法
configureCollectionViewLayout(for searchScope: SearchScope)
來設定集合視圖的排版。 - 根據不同的 SearchScope,這個方法將會有不同的排版行為。
7–2.使用 UICollectionViewCompositionalLayout
利用
NSCollectionLayoutSize, NSCollectionLayoutItem, NSCollectionLayoutGroup,
NSCollectionLayoutSection, NSCollectionLayoutBoundarySupplementaryItem
組合出一個 UICollectionViewCompositionalLayout。
這是一個反覆嘗試的過程,需要逐步建構並測試來查看排版效果。
7–3.調用新的排版設定方法
- 在
StoreItemContainerViewController
的prepare(for:)
方法中,將新的排版設定方法應用到StoreItemCollectionViewController
。
7–4.調整排版以適應不同的搜索範圍
- 當
搜索範圍(SearchScope)
不是.all
時,調整排版以更好地利用螢幕空間。
為此,需要在 StoreItemContainerViewController 中添加一個引用到
集合視圖控制器(collection view controller)的屬性。
7–5.更新排版設定
1. 在 handleFetchedItems(_:) 中,在應用快照之前,調用
configureCollectionViewLayout(for:) 來更新排版。
2. 這樣當搜索範圍變更時,排版也會相應地調整。
3. 否則快照會應用到之前選擇的 selectSearchScope 上,當從 "全部" 選項切換到其他選項
時將看不到內容。
7–6.使用 SearchScope 擴展來簡化排版邏輯
- 將
orthogonalScrollingBehavior
,groupItemCount
, 和groupWidthDimension
定義為SearchScope
的擴展屬性,使排版設定更加靈活。
在開發中,面對問題有許多解決方式。
一個方法是確定哪些屬性在兩種情境下是相同的,哪些是不同的。然後,將這些屬性分別提取出來定義。
在這個案例中,不同的屬性包括
orthogonalScrollingBehavior、groupItemCount和groupWidthDimension。
可以透過對 SearchScope 進行擴展,將這些屬性定義在其中。