-
Notifications
You must be signed in to change notification settings - Fork 68
/
Copy pathCollectionViewDiffableDataSource.swift
160 lines (140 loc) · 6.59 KB
/
CollectionViewDiffableDataSource.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#if os(iOS) || os(tvOS)
import UIKit
import DifferenceKit
/// A class for backporting `UICollectionViewDiffableDataSource` introduced in iOS 13.0+, tvOS 13.0+.
/// Represents the data model object for `UICollectionView` that can be applies the
/// changes with automatic diffing.
open class CollectionViewDiffableDataSource<SectionIdentifierType: Hashable, ItemIdentifierType: Hashable>: NSObject, UICollectionViewDataSource {
/// The type of closure providing the cell.
public typealias CellProvider = (UICollectionView, IndexPath, ItemIdentifierType) -> UICollectionViewCell?
/// The type of closure providing the supplementary view for element of kind.
public typealias SupplementaryViewProvider = (UICollectionView, String, IndexPath) -> UICollectionReusableView?
/// A closure to dequeue the views for element of kind.
public var supplementaryViewProvider: SupplementaryViewProvider?
private weak var collectionView: UICollectionView?
private let cellProvider: CellProvider
private let core = DiffableDataSourceCore<SectionIdentifierType, ItemIdentifierType>()
/// Creates a new data source.
///
/// - Parameters:
/// - collectionView: A collection view instance to be managed.
/// - cellProvider: A closure to dequeue the cell for items.
public init(collectionView: UICollectionView, cellProvider: @escaping CellProvider) {
self.collectionView = collectionView
self.cellProvider = cellProvider
super.init()
collectionView.dataSource = self
}
/// Applies given snapshot to perform automatic diffing update.
///
/// - Parameters:
/// - snapshot: A snapshot object to be applied to data model.
/// - animatingDifferences: A Boolean value indicating whether to update with
/// diffing animation.
/// - completion: An optional completion block which is called when the complete
/// performing updates.
public func apply(_ snapshot: DiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>, animatingDifferences: Bool = true, completion: (() -> Void)? = nil) {
core.apply(
snapshot,
view: collectionView,
animatingDifferences: animatingDifferences,
performUpdates: { collectionView, changeset, setSections in
collectionView.reload(using: changeset, setData: setSections)
},
completion: completion
)
}
/// Returns a new snapshot object of current state.
///
/// - Returns: A new snapshot object of current state.
public func snapshot() -> DiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType> {
return core.snapshot()
}
/// Returns an item identifier for given index path.
///
/// - Parameters:
/// - indexPath: An index path for the item identifier.
///
/// - Returns: An item identifier for given index path.
public func itemIdentifier(for indexPath: IndexPath) -> ItemIdentifierType? {
return core.itemIdentifier(for: indexPath)
}
/// Returns an index path for given item identifier.
///
/// - Parameters:
/// - itemIdentifier: An identifier of item.
///
/// - Returns: An index path for given item identifier.
public func indexPath(for itemIdentifier: ItemIdentifierType) -> IndexPath? {
return core.indexPath(for: itemIdentifier)
}
/// Returns the number of sections in the data source.
///
/// - Parameters:
/// - collectionView: A collection view instance managed by `self`.
///
/// - Returns: The number of sections in the data source.
public func numberOfSections(in collectionView: UICollectionView) -> Int {
return core.numberOfSections()
}
/// Returns the number of items in the specified section.
///
/// - Parameters:
/// - collectionView: A collection view instance managed by `self`.
/// - section: An index of section.
///
/// - Returns: The number of items in the specified section.
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return core.numberOfItems(inSection: section)
}
/// Returns a cell for item at specified index path.
///
/// - Parameters:
/// - collectionView: A collection view instance managed by `self`.
/// - indexPath: An index path for cell.
///
/// - Returns: A cell for row at specified index path.
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let itemIdentifier = core.unsafeItemIdentifier(for: indexPath)
guard let cell = cellProvider(collectionView, indexPath, itemIdentifier) else {
universalError("UICollectionView dataSource returned a nil cell for item at index path: \(indexPath), collectionView: \(collectionView), itemIdentifier: \(itemIdentifier)")
}
return cell
}
/// Returns a supplementary view for element of kind at specified index path.
///
/// - Parameters:
/// - collectionView: A collection view instance managed by `self`.
/// - kind: The kind of element to be display.
/// - indexPath: An index path for supplementary view.
///
/// - Returns: A supplementary view for element of kind at specified index path.
open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
guard let view = supplementaryViewProvider?(collectionView, kind, indexPath) else {
return UICollectionReusableView()
}
return view
}
/// Returns whether it is possible to edit a row at given index path.
///
/// - Parameters:
/// - collectionView: A collection view instance managed by `self`.
/// - section: An index of section.
///
/// - Returns: A boolean for row at specified index path.
open func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
return false
}
/// Moves a row at given index path.
///
/// - Parameters:
/// - collectionView: A collection view instance managed by `self`.
/// - sourceIndexPath: An index path for given cell position.
/// - destinationIndexPath: An index path for target cell position.
///
/// - Returns: Void.
public func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// Empty implementation.
}
}
#endif