WWDC20 之 iOS Modern Collection View

WWDC19开始,UICollectionView相比之前简单的DataSource、Delegate的形式多了一种新写法,通过DiffableDataSource支持了局部刷新、cell的方便增删改等;通过UICollectionViewCompositionalLayout 帮助开发者更简单地去构建复杂布局。下面给出了一些简单的特性实践,需要注意的是,也是最关键的一点,这些特性仅支持iOS13+ (部分iOS14+)

1. UICollectionViewCompositionalLayout

我们在写现有的layout的时候,了解到目前的collectionView有item和section两个维度。而在modern collectionview里,在这两者之间增加了一个Group纬度。为的就是更方便地创造出更复杂的布局:

image.png

有了group以后,我们可以嵌套多种排列的Item。这样有利有弊,好处不言而喻,坏处当然是理解起来又要多一个层级。

1.1 Group

  • Group 是新引入的组成布局的基本单元,它有三种形式

    • 水平(horizontal)

    • 垂直(vertical)

    • 自定义(custom)

    • Group 的大小页需要通过NSCollectionLayoutSize 决定。如果是自定义布局,需要传入一个 NSCollectionLayoutGroupCustomItemProvider 来决定这个 Group 中 Item 的布局方式。

    • 通过 Group 可以在同一个 Section 中实现不同的布局方式。定义如下:

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

}

具体的使用参见Demo (文末给到)

注:横滑样式可以用Group的方式实现了

1.2 Section && Item

section也迎来了一些更新

1.2.1 可以传入group进行初始化

 let section = NSCollectionLayoutSection(group: group)

1.2.2 加入NSCollectionLayoutAnchor 实现小红点或者未读消息视图


let badgeAnchor = NSCollectionLayoutAnchor(edges: [.top, .trailing],

fractionalOffset: CGPoint(x: 0.5, y: -0.5))

let badgeSize = NSCollectionLayoutSize(widthDimension: .absolute(16),

heightDimension: .absolute(16))

let badge = NSCollectionLayoutSupplementaryItem(layoutSize: badgeSize, elementKind: "badge", containerAnchor: badgeAnchor)

let item = NSCollectionLayoutItem(layoutSize: itemSize, supplementaryItems: [badge])

以上可以通过在Item上设置SupplementaryItem实现小红点。

1.2.3 控制Section的滚动模式

UICollectionLayoutSectionOrthogonalScrollingBehavior现在可以控制Section的滚动模式

主要是根据这个参数可以控制Section滚动时的表现。比如翻页的按页滚动、或者不减速滚动等,总体而言更多样了。

关于layout先到这里。还有一些更新和实例在官方Demo中均有体现。

2.DiffableDataSource

类似于DiffableDataSource的概念其实我们在IGList中有接触,通过为数据源设置不同的identifier实现数据源和UI的绑定。在刷新数据源时,只要重新计算diff,计算进行局部刷新,可以大大提高UICollectionView的性能。 在modern collectionview 中也引入了新的DiffableDataSource的概念,我们不再需要设置Datasource通过一系列数据源方法返回,而是通过一开始的绑定,通过snapshot进行刷新。

比如我要实现这样一个CollectionView:

三个section,每个section有自己的Item

image.png

具体代码如下:

Layout部分:

这里虽然看起来是一个tableview,我们也可以使用tableview实现,但是我选择使用iOS14的新属性:

UICollectionLayoutListConfiguration

今年WWDC20的session里,比较大的两个更新就是增加了outline展开收起样式的支持和新增UItableViewlike的 collectionView。也就意味着collectionView可以做UItableView的事情了(不再需要UItableView),同样,该样式还支持左滑删除等tableview的特色属性。

实现起来也很简单:


 func createLayout() -> UICollectionViewLayout {

 let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)

 return UICollectionViewCompositionalLayout.list(using: configuration)

 }


数据源部分:


 func configureDataSource() { 

 //设置cell的数据处理(绑定UI元素到数据源) 

 let cellRegi = UICollectionView.CellRegistration {

 (cell, indexPath, emoji) in

 var contentConfiguration = UIListContentConfiguration.valueCell()

 contentConfiguration.text = emoji;

 cell.contentConfiguration = contentConfiguration

 cell.accessories = [.disclosureIndicator()]

 }

 //设置dataSource 

 dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) {

 (collectionView, indexPath, item) -> UICollectionViewCell? in

 return collectionView.dequeueConfiguredReusableCell(using: cellRegi, for: indexPath, item: item.title)

 }

 }

  • 在需要刷新的时候,使用 DataSourceSnapshot 处理变更后的数据源,其有 append、delete、move、insert 等方法。DiffableDataSource 通过调用自身 apply 方法将 DataSourceSnapshot 变更后的数据更新同步到 UICollectionView。

  • 主要是引入了SnapShot ,快照的概念,我理解是处理DataSource 的一个数据中心。

 func applyInitialSnapshots() {

 //有 1 2 3 三个section

 for category in ["1","2","3"]{

 //每个section有两个item

 var sectionSnapshot = NSDiffableDataSourceSectionSnapshot()

 let items = [Item(title: "item" + category),Item(title: "item2" + category)];

 sectionSnapshot.append(items)

 dataSource.apply(sectionSnapshot, to: category, animatingDifferences: false)

 }

 }

关于列表元素的增删改操作如下:

通过数据快照,可以很方便地对列表进行局部刷新增删改查操作。而操作Item的原子元素其实是数据源。


 var snap =  dataSource.snapshot()

 snap.deleteSections(["2"]);

 snap.appendItems([Item(title: "item Insert")], toSection: "1")

 snap.deleteItems([Item(title: "item23")]);

 dataSource.apply(snap);

在这里我对Item这个model的定义是根据title的name区分identifier。所以传入一个new 的item,只要id一样就是同一个:


 struct Item: Hashable {

 static func == (lhs: TestViewController.Item, rhs: TestViewController.Item) -> Bool {

 return lhs.title == rhs.title;

 }

 let title: String

 init(title: String) {

 self.title = title

 }

 }

3.其他

Modern Collection Views 是iOS13推出iOS14持续更新的新概念,有兴趣的童鞋可以继续去https://developer.apple.com/news/?id=d9kd3m7g 看一下Session和Video,我这里只提到了部分更新,其实WWDC19 + 20 关于CollectionView的改造还是比较多的。总结出整体的大趋势是 去TableView化、推动DiffDataSource和支持更复杂的布局样式。

以上~

//上面截图的CollectionView的实现(完整代码)

官方demo:

https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views

题外话:

WWDC20可以看出苹果的未来在开发上的方向肯定是扶正Swift以及SwfitUI,iOS14 的Widgets仅支持SwiftUI开发。同样属于新特性的app clips 在官方演示中也是只用了SwfitUI(鉴于特殊性还是支持UIKit)。随着Swift的ABI稳定,相信苹果还会推出更多新特性新功能。

你可能感兴趣的:(WWDC20 之 iOS Modern Collection View)