iOS 组合布局(UICollectionViewCompositionalLayout)的实际应用案例
案例 1:电商 App 首页(多模块混合布局)
场景描述
电商首页通常是「顶部 Banner → 分类入口(2 行 4 列)→ 爆款推荐(1 行 2 列)→ 商品列表(2 列网格)」的组合,不同模块用不同布局规则,这是组合布局最典型的应用场景。
布局思路
- 拆分 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 动态流(瀑布流 + 混合排版)
场景描述
朋友圈 / 小红书类动态流,每条动态包含「文字 + 1/3/4/9 张图片」,图片区域需要瀑布流效果(不同高度),文字区域自适应高度,整体布局灵活且不规则。
布局思路
- 单个 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 列表(多样式混合布局)
场景描述
新闻 / 资讯 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
}
}
}
总结
- 组合布局的核心是分层拆解:将复杂界面拆分为「Item-Group-Section」,不同模块用不同尺寸 / 排列方式,再组合起来;
- 实际开发中优先用
fractional(比例)和estimated(预估)尺寸,适配不同屏幕; - 多样式布局通过「Section 区分」或「动态调整 Item/Group 尺寸」实现,Supplementary View 可灵活添加头部 / 尾部元素;
- 瀑布流的核心是给 Item 设置随机 / 动态高度,配合
estimated尺寸让布局自适应。

浙公网安备 33010602011771号