概述:
在iOS 13贩挣、iOS 14以后揍堰,UICollectionView 進(jìn)行了很多變化。其中最主要的兩點(diǎn)就是:
- UICollectionViewCompositionalLayout
組合布局,一種集合視圖布局,它是可組合的惜论、靈活的和快速的,允許您為內(nèi)容構(gòu)建任何類型的視覺安排止喷。 - UICollectionViewDiffableDataSource
一種特殊類型的數(shù)據(jù)源馆类,它提供了簡單高效地管理集合視圖數(shù)據(jù)和用戶界面更新所需的行為。
一弹谁、UICollectionViewCompositionalLayout介紹
自從iOS 6出現(xiàn)了UICollectionView乾巧,在iOS 13以前我們創(chuàng)建并顯示,是通過UICollectionViewFlowLayout布局做到的预愤。
其中UICollectionViewFlowLayout擁有
@property (nonatomic) CGFloat minimumLineSpacing;
@property (nonatomic) CGFloat minimumInteritemSpacing;
@property (nonatomic) CGSize itemSize;
@property (nonatomic) CGSize estimatedItemSize API_AVAILABLE(ios(8.0)); // defaults to CGSizeZero - setting a non-zero size enables cells that self-size via -preferredLayoutAttributesFittingAttributes:
@property (nonatomic) UICollectionViewScrollDirection scrollDirection; // default is UICollectionViewScrollDirectionVertical
@property (nonatomic) CGSize headerReferenceSize;
@property (nonatomic) CGSize footerReferenceSize;
@property (nonatomic) UIEdgeInsets sectionInset;
等屬性沟于,來控制每一個(gè)item在UICollectionView中的顯示。
到了iOS 13植康,蘋果引入了UICollectionViewCompositionalLayout用來設(shè)置UICollectionView的布局旷太。
總覽
合成布局是一種集合視圖布局。 它的設(shè)計(jì)具有可組合性销睁,靈活性和快速性供璧,可讓您通過將每個(gè)較小的組件組合(或合成)成完整的布局來為內(nèi)容構(gòu)建任何形式的視覺布置。
合成布局由一個(gè)或多個(gè)部分組成冻记,這些部分將布局分解為不同的視覺分組睡毒。 每個(gè)部分都是由各個(gè)項(xiàng)目組成的組,這些項(xiàng)目是要顯示的最小數(shù)據(jù)單元檩赢。 一組人員可以將其項(xiàng)目布置在水平行,垂直列或自定義排列中。
您可以通過以下方式將組件組合在一起:從項(xiàng)目(item)到一個(gè)組(group)贞瞒,從組到一個(gè)節(jié)(section)偶房,最后到完整的布局。
創(chuàng)建網(wǎng)絡(luò)布局的代碼如下:
private func createLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.2),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalWidth(0.2))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
subitems: [item])
let section = NSCollectionLayoutSection(group: group)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
知識(shí)點(diǎn):1.NSCollectionLayoutSize為:
每個(gè)組件的尺寸(NSCollectionLayoutDimension)的一對(duì)寬军浆、高的尺寸棕洋。集合視圖布局的每個(gè)組件都有一個(gè)明確的大小。
原文:
A size is a pair of dimensions (NSCollectionLayoutDimension): a width dimension and a height dimension. Every component of a collection view layout has an explicit size.
知識(shí)點(diǎn):2.NSCollectionLayoutDimension為:
集合視圖中項(xiàng)目尺寸(寬度或高度)的單個(gè)尺寸乒融。
集合視圖中的每個(gè)項(xiàng)目都有一個(gè)明確的寬度尺寸和高度尺寸掰盘,這兩個(gè)尺寸組合在一起定義了項(xiàng)目的尺寸(NSCollectionLayoutSize)。
您可以使用絕對(duì)值赞季,估計(jì)值或分?jǐn)?shù)值來表示項(xiàng)目的尺寸愧捕。
使用絕對(duì)值來指定確切的尺寸,例如44 x 44點(diǎn)正方形:
let absoluteSize = NSCollectionLayoutSize(widthDimension: .absolute(44),
heightDimension: .absolute(44))
如果內(nèi)容的大小可能在運(yùn)行時(shí)發(fā)生更改(例如申钩,在加載數(shù)據(jù)時(shí)或響應(yīng)系統(tǒng)字體大小更改時(shí))次绘,請(qǐng)使用估計(jì)值。 您提供初始估計(jì)大小撒遣,然后系統(tǒng)會(huì)計(jì)算實(shí)際值邮偎。
(這個(gè)應(yīng)該是為了根據(jù)內(nèi)容自適應(yīng)使用的)
let estimatedSize = NSCollectionLayoutSize(widthDimension: .estimated(200),
heightDimension: .estimated(100))
使用分?jǐn)?shù)值來定義相對(duì)于商品容器尺寸的值。 此選項(xiàng)簡化了寬高比的指定义黎。
//以下項(xiàng)目的寬度和高度都等于其容器(父view)寬度的20%禾进,從而創(chuàng)建一個(gè)隨容器大小變化而增大和縮小的正方形。
let fractionalSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.2),
heightDimension: .fractionalWidth(0.2))
知識(shí)點(diǎn):3. 使用horizontal(layoutSize:subitem:count:)創(chuàng)建布局
使用count參數(shù)中指定的確切項(xiàng)數(shù)創(chuàng)建一個(gè)組廉涕。這種方法簡化了精確指定一個(gè)組包含多少項(xiàng)的過程泻云。在這種情況下,count參數(shù)優(yōu)先于itemSize火的,并且自動(dòng)計(jì)算項(xiàng)大小以適合指定的項(xiàng)數(shù)壶愤。
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 3)
知識(shí)點(diǎn):4. NSCollectionLayoutItem
集合視圖布局的最基本組成部分
總覽
一項(xiàng)是關(guān)于如何在集合視圖中調(diào)整大小,空間和安排單個(gè)內(nèi)容的藍(lán)圖馏鹤。一個(gè)項(xiàng)目代表在屏幕上呈現(xiàn)的單個(gè)視圖征椒。通常,項(xiàng)目是一個(gè)單元格湃累,但項(xiàng)目可以是補(bǔ)充視圖勃救,例如頁眉,頁腳和其他裝飾治力。
例如蒙秒,在“照片”應(yīng)用中,一個(gè)項(xiàng)目可能代表一張照片宵统。在App Store應(yīng)用程序中晕讲,項(xiàng)目可能是一個(gè)單元格,用于在特色應(yīng)用程序列表中顯示有關(guān)單個(gè)應(yīng)用程序的信息,例如應(yīng)用程序圖標(biāo)瓢省,應(yīng)用程序名稱弄息,標(biāo)語和下載按鈕。
(見上圖UICollectionViewCompositionalLayout總覽)
知識(shí)點(diǎn):5. NSCollectionLayoutGroup
一組項(xiàng)目的容器勤婚,用于沿著路徑布置項(xiàng)目摹量。
總覽
組確定集合視圖中的items如何相對(duì)于彼此進(jìn)行布局÷ǎ可以將items按照行缨称、列或自定義布置到Group中。
一個(gè)組確定有關(guān)如何相互呈現(xiàn)項(xiàng)目的規(guī)則祝迂,但其本身不呈現(xiàn)任何內(nèi)容睦尽。
例如,在“照片”應(yīng)用中液兽,一組項(xiàng)目是一排照片骂删。在App Store應(yīng)用程序中,組可能是垂直列中排列的一列單元格(項(xiàng)目)四啰。
(見上圖UICollectionViewCompositionalLayout總覽)
因?yàn)榻M是NSCollectionLayoutItem的子類宁玫,所以它的行為類似于Item。您可以將一個(gè)組與其他項(xiàng)目和組組合成更復(fù)雜的布局柑晒。
多個(gè)group組合欧瘪,以上顯示可以用代碼實(shí)現(xiàn)為:
//先定義左邊大的主item,設(shè)置寬度占整個(gè)group的70%匙赞,高度為100%
let leadingItem = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.7),
heightDimension: .fractionalHeight(1.0)))
leadingItem.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
//再定義右邊兩個(gè)小的為一組佛掖,按照豎排列,2個(gè)一組
//兩個(gè)小的item涌庭,設(shè)置寬度占整個(gè)group的100%芥被,高度為50%
let trailingItem = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.5)))
trailingItem.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
let trailingGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.3),
heightDimension: .fractionalHeight(1.0)),
subitem: trailingItem, count: 2)
//再把上面的leadingItem和trailingGroup放到一個(gè)組里
let nestedGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.4)),
subitems: [leadingItem, trailingGroup])
知識(shí)點(diǎn):6. NSCollectionLayoutSection
一個(gè)將一個(gè)個(gè)Group組合為不同的可視分組的容器。
總覽
集合視圖布局具有一個(gè)或多個(gè)section坐榆。 各section提供了一種將布局分成不同部分的方法拴魄。
每個(gè)section可以具有與集合視圖中其他section相同或不同的布局。 section的布局由用于創(chuàng)建section的組(NSCollectionLayoutGroup)的屬性確定席镀。
例如匹中,在“照片”應(yīng)用中,“年份”頁面中的每個(gè)部分都使用相同的布局豪诲。 在App Store中顶捷,“應(yīng)用程序”頁面顯示具有不同內(nèi)容排列的幾個(gè)部分。
(見上圖UICollectionViewCompositionalLayout總覽)
通過以上1屎篱、2服赎、3葵蒂、4、5重虑、6各部分刹勃,就可以組成一個(gè)UICollectionViewCompositionalLayout了。
let layout = UICollectionViewCompositionalLayout(section: section)
var collectionView: UICollectionView! = nil
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
就可以初始化一個(gè)collectionView了嚎尤。
如果擁有多個(gè)section,并且section之間顯示還不一樣伍宦,可以用如下方法實(shí)現(xiàn)
func createLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
if sectionIndex == 0{
let section = NSCollectionLayoutSection(group: Group0)
return section
} else {
let section = NSCollectionLayoutSection(group: Group1)
return section
}
}
return layout
}
知識(shí)點(diǎn):7. NSCollectionLayoutSupplementaryItem
可以使用NSCollectionLayoutSupplementaryItem給item, group, section來添加角標(biāo)等信息芽死。
用于向集合視圖中的項(xiàng)目添加額外的視覺裝飾(例如徽章或框架)的對(duì)象。
例子:定義UICollectionViewCompositionalLayout時(shí)次洼,在每個(gè)item上加角標(biāo)
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-element-kind",
containerAnchor: badgeAnchor)
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.2),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize, supplementaryItems: [badge])
給UICollectionViewDiffableDataSource添加屬性
let supplementaryRegistration = UICollectionView.SupplementaryRegistration<BadgeSupplementaryView>(elementKind: "badge-element-kind") {
(badgeView, string, indexPath) in
let hasBadgeCount = (indexPath.row%2) > 0//奇數(shù)個(gè)時(shí)顯示角標(biāo)
// Set the badge count as its label (and hide the view if the badge count is zero).
badgeView.label.text = "\(indexPath.row)"
badgeView.isHidden = !hasBadgeCount
}
dataSource.supplementaryViewProvider = {
return self.collectionView.dequeueConfiguredReusableSupplementary(using: supplementaryRegistration, for: $2)
}
得到結(jié)果為:
知識(shí)點(diǎn):8. 用UICollectionView實(shí)現(xiàn)TableView樣式
在 iOS14 中,用 CollectionView 實(shí)現(xiàn)一個(gè) TableView 樣式的列表非常簡單关贵。
func createLayout() -> UICollectionViewLayout {
let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
return UICollectionViewCompositionalLayout.list(using: configuration)
}
其中insetGrouped為樣式。還有plain卖毁、grouped揖曾、insetGrouped、sidebar亥啦、sidebarPlain等樣式炭剪。
二、注冊(cè)初始化Cell
iOS 14提供了一個(gè)新方法:UICollectionView.CellRegistration用來注冊(cè)Cell
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { cell, indexPath, item in
var contentConfiguration = cell.defaultContentConfiguration()
contentConfiguration.text = "\(item)"
contentConfiguration.textProperties.color = .lightGray
cell.contentConfiguration = contentConfiguration
}
三翔脱、UICollectionViewDiffableDataSource
這是iOS 13新提出的方法奴拦。
用于管理數(shù)據(jù)和為集合視圖提供單元格的對(duì)象。
概述
diffable數(shù)據(jù)源對(duì)象是一種特殊類型的數(shù)據(jù)源届吁,與collection view一起工作错妖。它提供了以簡單、高效的方式管理collection view數(shù)據(jù)和UI更新所需的行為疚沐。它還符合UICollectionViewDataSource協(xié)議暂氯,并為該協(xié)議的所有方法提供實(shí)現(xiàn)。
要用數(shù)據(jù)填充collection view亮蛔,請(qǐng)執(zhí)行以下操作:
- 將可擴(kuò)散數(shù)據(jù)源連接到collection view痴施。
- 實(shí)現(xiàn)單元提供程序以配置collection view的cells 。
- 生成數(shù)據(jù)的當(dāng)前狀態(tài)尔邓。
- 在UI中顯示數(shù)據(jù)晾剖。
要將可擴(kuò)散數(shù)據(jù)源連接到集合視圖,可以使用其init(collectionView:cellProvider:)與要在view中傳遞數(shù)據(jù)的初始值設(shè)定項(xiàng)相關(guān)聯(lián)梯嗽。您還將傳入一個(gè)cell提供程序齿尽,在該程序中配置每個(gè)單元格以確定如何在UI中顯示數(shù)據(jù)。
知識(shí)點(diǎn):1. 將Diffable Data Source連接到collection view
dataSource = UICollectionViewDiffableDataSource.init(collectionView: collectionView, cellProvider: {
(collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
})
知識(shí)點(diǎn):2. NSDiffableDataSourceSnapshot
然后灯节,生成數(shù)據(jù)的當(dāng)前狀態(tài)循头,并通過構(gòu)造和應(yīng)用快照在UI中顯示數(shù)據(jù):
視圖中數(shù)據(jù)在特定時(shí)間點(diǎn)的狀態(tài)表示绵估。
概述
Diffable data sources使用快照為collection views 和 table views提供數(shù)據(jù)。通過快照卡骂,可以設(shè)置在視圖中顯示的數(shù)據(jù)的初始狀態(tài)国裳,然后更新該數(shù)據(jù)。
快照中的數(shù)據(jù)由要顯示的sections和items組成全跨,按要顯示的特定順序排列缝左。您可以通過添加adding、刪除deleting或移動(dòng)moving sections和items來配置要顯示的內(nèi)容浓若。重要
每個(gè)sections和items都必須具有符合哈希協(xié)議的唯一標(biāo)識(shí)符渺杉。
要使用快照在視圖中顯示數(shù)據(jù),請(qǐng)執(zhí)行以下操作:
創(chuàng)建快照并用要顯示的數(shù)據(jù)的狀態(tài)填充它挪钓。
應(yīng)用快照以反映UI中的更改是越。
您可以通過以下方式之一創(chuàng)建和配置快照:
創(chuàng)建一個(gè)空快照,然后向其附加節(jié)和項(xiàng)碌上。
通過調(diào)用diffable數(shù)據(jù)源的snapshot()方法獲取當(dāng)前快照倚评,然后修改該快照以反映要顯示的數(shù)據(jù)的新狀態(tài)。
var snapshot = NSDiffableDataSourceSnapshot<Section, Int>()
snapshot.appendSections([.main])
snapshot.appendItems(Array(0..<30))
dataSource.apply(snapshot, animatingDifferences: false)
其中Section具有符合哈希協(xié)議的唯一標(biāo)識(shí)符
enum Section {
case main
}