-
Notifications
You must be signed in to change notification settings - Fork 0
/
UICollectionView+Extensions.swift
165 lines (147 loc) · 6.8 KB
/
UICollectionView+Extensions.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
161
162
163
164
165
//
// UICollectionView+Extensions.swift
// OYExtensions
//
// Created by osmanyildirim
//
import UIKit
extension UICollectionView {
/// Register UICollectionViewCell with class name
/// - Parameter type: UICollectionViewCell class
public func oy_register<C: UICollectionViewCell>(_ type: C.Type) {
register(C.self, forCellWithReuseIdentifier: C.oy_reuseIdentifier)
}
/// Register UICollectionViewCell array with class names
/// - Parameter types: UICollectionViewCell classes array
public func oy_register<C: UICollectionViewCell>(types: C.Type...) {
_ = types.map { oy_register($0) }
}
/// Register UICollectionViewCell with nib name and bundle
/// - Parameters:
/// - nib: nib class
/// - bundle: bundle
public func oy_register<C: UICollectionViewCell>(nib: C.Type, bundle: Bundle = .main) {
register(UINib(nibName: nib.oy_reuseIdentifier, bundle: bundle), forCellWithReuseIdentifier: C.oy_reuseIdentifier)
}
/// Register UICollectionViewCell with nib name array and bundle
/// - Parameters:
/// - nibs: nib classes
/// - bundle: bundle
public func oy_register<C: UICollectionViewCell>(nibs: C.Type..., bundle: Bundle = .main) {
_ = nibs.map { oy_register(nib: $0, bundle: bundle) }
}
/// Register UICollectionReusableView with class name
/// - Parameters:
/// - kind: `UICollectionView.elementKindSectionHeader` or `UICollectionView.elementKindSectionFooter`
/// - type: UICollectionReusableView class
public func oy_register<C: UICollectionReusableView>(supplementaryViewOfKind kind: String, type: C.Type) {
register(C.self, forSupplementaryViewOfKind: kind, withReuseIdentifier: C.oy_reuseIdentifier)
}
/// Register UICollectionReusableView with nib name and bundle
/// - Parameters:
/// - kind: `UICollectionView.elementKindSectionHeader` or `UICollectionView.elementKindSectionFooter`
/// - nib: nib class
/// - bundle: bundle
public func oy_register<C: UICollectionReusableView>(supplementaryViewOfKind kind: String, nib: C.Type, bundle: Bundle = .main) {
register(UINib(nibName: nib.oy_reuseIdentifier, bundle: bundle), forSupplementaryViewOfKind: kind, withReuseIdentifier: C.oy_reuseIdentifier)
}
/// Register UICollectionReusableView with nib names and bundle
/// - Parameters:
/// - kind: `UICollectionView.elementKindSectionHeader` or `UICollectionView.elementKindSectionFooter`
/// - nibs: nib classes
/// - bundle: bundle
public func oy_register<C: UICollectionReusableView>(supplementaryViewOfKind kind: String, nibs: C.Type..., bundle: Bundle = .main) {
_ = nibs.map { oy_register(supplementaryViewOfKind: kind, nib: $0) }
}
/// Dequeue reusable UICollectionViewCell using class name
/// - Parameters:
/// - type: UICollectionViewCell class
/// - indexPath: IndexPath
/// - Returns: UICollectionViewCell
public func oy_dequeueReusableCell<C: UICollectionViewCell>(_ type: C.Type, for indexPath: IndexPath) -> C {
guard let cell = dequeueReusableCell(withReuseIdentifier: type.oy_reuseIdentifier, for: indexPath) as? C else {
fatalError("\(#function) Unable to dequeue reusable cell of type `\(type)`")
}
return cell
}
/// Dequeue reusable UICollectionReusableView using class name
/// - Parameters:
/// - kind: `UICollectionView.elementKindSectionHeader` or `UICollectionView.elementKindSectionFooter`
/// - type: UICollectionReusableView class
/// - indexPath: IndexPath
/// - Returns: UICollectionReusableView
public func oy_dequeueReusableSupplementaryView<C: UICollectionReusableView>(ofKind kind: String, type: C.Type, for indexPath: IndexPath) -> C {
guard let cell = dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: C.oy_reuseIdentifier, for: indexPath) as? C else {
fatalError("\(#function) Unable to dequeue reusable cell of type `\(type)`")
}
return cell
}
/// Item(s) count of UICollectionView
public var oy_itemCount: Int {
var section = 0
var itemsCount = 0
while section < numberOfSections {
itemsCount += numberOfItems(inSection: section)
section += 1
}
return itemsCount
}
/// Index path of last item in UICollectionView
public var oy_indexPathForLastItem: IndexPath? {
oy_indexPathForLastItem(inSection: oy_lastSection)
}
/// Index of last section in UICollectionView
public var oy_lastSection: Int {
numberOfSections > 0 ? numberOfSections - 1: 0
}
/// IndexPath's of visible cell(s) in UICollectionView
public var oy_visibleCellsIndexPaths: [IndexPath] {
let visibleIndexPaths = indexPathsForVisibleItems.filter { indexPath in
guard let layoutAttribute = layoutAttributesForItem(at: indexPath) else { return false }
let isVisible = bounds.contains(layoutAttribute.frame)
return isVisible
}
return visibleIndexPaths
}
/// UICollectionView's reload completion handler
/// - Parameter completion: completion handler
public func oy_reloadDataCompletion(completion: @escaping () -> Void) {
CATransaction.begin()
CATransaction.setCompletionBlock {
completion()
}
self.reloadData()
CATransaction.commit()
}
/// Scroll to UICollectionView with indexPath, scrollPosition and animated
/// - Parameters:
/// - indexPath: indexPath
/// - scrollPosition: scroll position: top, bottom etc.
/// - animated: if the should be animated
public func oy_scrollToItem(at indexPath: IndexPath, at scrollPosition: UICollectionView.ScrollPosition, animated: Bool) {
guard oy_isValidIndexPath(indexPath) else { return }
scrollToItem(at: indexPath, at: scrollPosition, animated: animated)
}
/// Index path of last item in UICollectionView by section
/// - Parameter section: section number
/// - Returns: indexPath
private func oy_indexPathForLastItem(inSection section: Int) -> IndexPath? {
guard section >= 0 else {
return nil
}
guard section < numberOfSections else {
return nil
}
guard numberOfItems(inSection: section) > 0 else {
return IndexPath(item: 0, section: section)
}
return IndexPath(item: numberOfItems(inSection: section) - 1, section: section)
}
/// Checks the validity of IndexPath of UICollectionView
func oy_isValidIndexPath(_ indexPath: IndexPath) -> Bool {
return indexPath.section >= 0 &&
indexPath.item >= 0 &&
indexPath.section < numberOfSections &&
indexPath.item < numberOfItems(inSection: indexPath.section)
}
}