Ba4eeb14b71c453d8d979539235239ad
UICollectionView 全新布局框架:UICollectionViewCompositionalLayout

WWDC 2019 Session 215 - Advances in Collection View Layout

引言

在 iOS 6.0 苹果发布了UICollectionView , 在之前一直使用 UICollectionViewFlowLayout 来做 UICollectionView 的布局。在最新的 wwdc 2019 中,苹果发布了全新的 UICollectionViewCompositionalLayout 来对 UICollectionView进行布局。

UICollectionViewCompositionalLayout 简介

在之前要自定义一个 UICollectionView 的布局,都是通过继承 UICollectionViewFlowLayout 并重写其中的代理方法来实现。在 iOS13 中,苹果发布了新的 UICollectionViewCompositionalLayout API , 主要包括 NSCollectionLayoutSize ,NSCollectionLayoutItem , NSCollectionLayoutGroup 和 NSCollectionLayoutSection 四个类的组合,来快速的实现 UICollectionView 自定义布局。
在 UICollectionViewCompositionalLayout 中,Item > Group > Section > Layout 他们之间也可以相互组合。

NSCollectionLayoutSize

他决定了一个元素的大小。表达一个元素的 Size 有三种方法:

  1. fractionalWidth 代表了一个元素相对于他的父视图的比例。
let size = NSCollectionLayoutDimension(widthDimension: .fractionalWidth(0.25), heightDimension: .fractionalWidth(0.25))
  1. absolute 代表着将元素的宽或者高写死一个绝对的值。
let heightDimension = NSCollectionLayoutDimension.absolute(200)
  1. estimated 代表预估高度。一般用于自适应大小,这里会根据内部的约束决定元素的大小。
let heightDimension = NSCollectionLayoutDimension.estimated(200)

NSCollectionLayoutItem

class NSCollectionLayoutItem {
    convenience init(layoutSize: NSCollectionLayoutSize)
    var contentInsets: NSDirectionalEdgeInsets
}

NSCollectionLayoutItem这里描述了一个 Item 得布局,通过 NSCollectionLayoutSize 决定一个Item得大小,用法可以参考上面的 NSCollectionLayoutSize 定义。通过 contentInsets 来决定这个 Item 内凹的大小。

NSCollectionLayoutGroup

class NSCollectionLayoutGroup: NSCollectionLayoutItem { 
    class func horizontal(layoutSize: NSCollectionLayoutSize, subitems: [NSCollectionLayoutItem]) -> Self 
    class func vertical(layoutSize: NSCollectionLayoutSize, subitems: [NSCollectionLayoutItem]) -> Self 
    class func custom(layoutSize: NSCollectionLayoutSize, itemProvider: NSCollectionLayoutGroupCustomItemProvider) -> Self
}

NSCollectionLayoutGroup 是在 UICollectionViewCompositionalLayout 中引入得一个全新的概念。他分别有水平(horizontal),垂直(vertical), 自定义(custom)三中布局方式。他需要通过 NSCollectionLayoutSize 决定这个 group 得大小。而在自定义中需要传入一个 NSCollectionLayoutGroupCustomItemProvider 来决定这个 group 中 Item 得布局方式。通过 NSCollectionLayoutGroup 我们可以实现在同一个 section 中实现不同得布局方式。

NSCollectionLayoutSection

class NSCollectionLayoutSection {
    convenience init(layoutGroup: NSCollectionLayoutGroup) 
    var contentInsets: NSDirectionalEdgeInsets
}

这里 Section 和之前 collectionView 得 Section 的定义类似,NSCollectionLayoutSize 决定一个 Section 得大小。通过 contentInsets 来决定这个 Section 内凹的大小。

高级布局

NSCollectionLayoutAnchor

在 item 中,我们可能需要给他加上小红点或者未读消息数,在 UICollectionViewCompositionalLayout 中,我们可以通过 NSCollectionLayoutSupplementaryItem 和 NSCollectionLayoutAnchor 这两个类来去定义一个这样的视图。

```
// NSCollectionLayoutAnchor
let badgeAnchor = NSCollectionLayoutAnchor(edges: [.top, .trailing],
fractionalOffset: CGPoint(x: 0.3, y: -0.3))
let badgeSize = NSCollectionLayoutSize(widthDimension: .absolute(20),
heightDimension: .absolute(20))
let badge = NSCollectionLayoutSupplementaryItem(layoutSize: badgeSize,
elementKind: "badge",

top Created with Sketch.