案例 1:電商 App 首頁(多模塊混合佈局)
場景描述
佈局思路
- 拆分 4 個 Section,分別對應 Banner、分類、爆款、商品;
- 每個 Section 獨立配置 Group/Item 尺寸,通過
contentInsets控制間距; - Banner 用全屏寬度的 Item,分類用小尺寸網格,商品用標準 2 列網格。
核心代碼(關鍵是多 Section 佈局配置)
swift
func createHomeLayout() -> UICollectionViewCompositionalLayout {
// 用閉包配置不同Section的佈局
return UICollectionViewCompositionalLayout { sectionIndex, _ -> NSCollectionLayoutSection? in
switch sectionIndex {
case 0: // 1. Banner區(全屏寬,固定高度)
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(200)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: itemSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = .init(top: 10, leading: 0, bottom: 10, trailing: 0)
return section
case 1: // 2. 分類入口(2行4列,正方形Item)
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.25),
heightDimension: .fractionalHeight(1.0)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .init(top: 5, leading: 5, bottom: 5, trailing: 5)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(80) // 2行 → 每組高度80,對應單個Item高度40
)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
// 2行:通過重複Group實現
section.repeatBoundarySupplementaryItems = []
return section
case 2: // 3. 爆款推薦(1行2列,寬高比16:9)
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.5),
heightDimension: .fractionalHeight(1.0)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .init(top: 5, leading: 5, bottom: 5, trailing: 5)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(180) // 16:9 → 寬度屏寬,高度180
)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
return section
case 3: // 4. 商品列表(2列網格,自適應高度)
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.5),
heightDimension: .estimated(250) // 預估高度,適配不同商品卡片
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .init(top: 5, leading: 5, bottom: 5, trailing: 5)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(250)
)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
return section
default:
return nil
}
}
}
案例 2:社交 App 動態流(瀑布流 + 混合排版)
場景描述
佈局思路
- 單個 Section 適配所有動態,通過
estimated尺寸實現動態高度; - 圖片組根據圖片數量動態調整 Item 數量和尺寸(1 張全屏、3 張 1 行 3 列、9 張 3 行 3 列);
- 文字區域作為 Supplementary View 嵌入,和圖片區域組合成完整動態。
核心代碼(瀑布流核心邏輯)
swift
func createFeedLayout() -> UICollectionViewCompositionalLayout {
// 1. 文字區域(Supplementary View)
let headerSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(80) // 自適應文字高度
)
let header = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerSize,
elementKind: "textHeader",
alignment: .top
)
// 2. 圖片Item(根據數量動態調整尺寸)
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0/3), // 3列基礎
heightDimension: .fractionalHeight(1.0)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .init(top: 2, leading: 2, bottom: 2, trailing: 2)
// 3. 圖片Group(瀑布流核心:預估高度)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(200) // 圖片高度隨機,預估200
)
// 這裏可根據圖片數量動態生成subitems(比如1張時itemSize設為1.0)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
// 4. 整體Section
let section = NSCollectionLayoutSection(group: group)
section.boundarySupplementaryItems = [header] // 加入文字頭部
section.contentInsets = .init(top: 10, leading: 10, bottom: 10, trailing: 10)
return UICollectionViewCompositionalLayout(section: section)
}
// 補充:在數據源中根據圖片數量調整Item尺寸
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let feed = feeds[indexPath.item]
switch feed.imageCount {
case 1:
return CGSize(width: collectionView.bounds.width - 20, height: CGFloat.random(in: 150...300)) // 隨機高度實現瀑布流
case 3,4:
return CGSize(width: (collectionView.bounds.width - 30)/3, height: CGFloat.random(in: 80...150))
case 9:
return CGSize(width: (collectionView.bounds.width - 40)/3, height: (collectionView.bounds.width - 40)/3)
default:
return CGSize(width: (collectionView.bounds.width - 30)/2, height: CGFloat.random(in: 100...200))
}
}
案例 3:資訊 App 列表(多樣式混合佈局)
場景描述
佈局思路
- 單個 Section,通過 Item 的
layoutSize動態區分不同樣式; - 左圖右文:Group 水平排列(圖片 Item + 文字 Item);
- 上圖下文:Group 垂直排列(圖片 Item + 文字 Item);
- 純文字:直接用全屏寬的 Item。
核心代碼(多樣式佈局)
swift
func createNewsLayout() -> UICollectionViewCompositionalLayout {
return UICollectionViewCompositionalLayout { sectionIndex, _ -> NSCollectionLayoutSection? in
// 通用配置:Section間距
let sectionInsets = NSDirectionalEdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16)
// 定義不同樣式的Item/Group
func createTextOnlyItem() -> NSCollectionLayoutItem {
// 純文字Item:全屏寬,自適應高度
let size = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(100)
)
let item = NSCollectionLayoutItem(layoutSize: size)
return item
}
func createLeftImageRightTextGroup() -> NSCollectionLayoutGroup {
// 左圖(1/3寬)+ 右文(2/3寬)
let imageItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1/3),
heightDimension: .fractionalHeight(1.0)
)
let imageItem = NSCollectionLayoutItem(layoutSize: imageItemSize)
let textItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(2/3),
heightDimension: .fractionalHeight(1.0)
)
let textItem = NSCollectionLayoutItem(layoutSize: textItemSize)
textItem.contentInsets = .init(top: 0, leading: 10, bottom: 0, trailing: 0)
// Group:固定高度120
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(120)
)
return NSCollectionLayoutGroup.horizontal(
layoutSize: groupSize,
subitems: [imageItem, textItem]
)
}
func createTopImageBottomTextGroup() -> NSCollectionLayoutGroup {
// 上圖(全屏寬)+ 下文(自適應高度)
let imageItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(180)
)
let imageItem = NSCollectionLayoutItem(layoutSize: imageItemSize)
let textItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(80)
)
let textItem = NSCollectionLayoutItem(layoutSize: textItemSize)
textItem.contentInsets = .init(top: 10, leading: 0, bottom: 0, trailing: 0)
// Group:垂直排列
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(260)
)
return NSCollectionLayoutGroup.vertical(
layoutSize: groupSize,
subitems: [imageItem, textItem]
)
}
// 根據數據類型選擇佈局
let newsType = newsList[sectionIndex].type
var group: NSCollectionLayoutGroup!
switch newsType {
case .textOnly:
let item = createTextOnlyItem()
group = NSCollectionLayoutGroup.horizontal(layoutSize: item.layoutSize, subitems: [item])
case .leftImageRightText:
group = createLeftImageRightTextGroup()
case .topImageBottomText:
group = createTopImageBottomTextGroup()
}
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = sectionInsets
return section
}
}
案例 4:工具類 App 設置頁(分組列表 + 網格混合)
場景描述
佈局思路
- 每個設置分組對應一個 Section,Section 頭部是分組標題;
- 單行設置項:Group 水平排列(文字 Item + 開關 Item);
- 多行功能入口:Group 水平排列多個小尺寸 Item,重複多行。
核心代碼(關鍵是分組標題 + 單行佈局)
swift
func createSettingsLayout() -> UICollectionViewCompositionalLayout {
// 1. 分組標題(Supplementary View)
let headerSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(44)
)
let header = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerSize,
elementKind: UICollectionView.elementKindSectionHeader,
alignment: .top
)
return UICollectionViewCompositionalLayout { sectionIndex, _ -> NSCollectionLayoutSection? in
let settingGroup = settings[sectionIndex]
switch settingGroup.type {
case .singleRow: // 單行設置項(文字+開關)
let textItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.8),
heightDimension: .fractionalHeight(1.0)
)
let textItem = NSCollectionLayoutItem(layoutSize: textItemSize)
let switchItemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.2),
heightDimension: .fractionalHeight(1.0)
)
let switchItem = NSCollectionLayoutItem(layoutSize: switchItemSize)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(44) // 標準行高
)
let group = NSCollectionLayoutGroup.horizontal(
layoutSize: groupSize,
subitems: [textItem, switchItem]
)
let section = NSCollectionLayoutSection(group: group)
section.boundarySupplementaryItems = [header] // 加入分組標題
return section
case .grid: // 網格功能入口(3列)
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1/3),
heightDimension: .fractionalHeight(1.0)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(88) // 2行 → 每行44
)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.boundarySupplementaryItems = [header]
// 重複Group實現多行
section.orthogonalScrollingBehavior = .none // 禁止橫向滾動
return section
}
}
}