Last active
March 28, 2019 05:40
-
-
Save shaps80/56f6f9c86fd9e209eee5f864311a70dd to your computer and use it in GitHub Desktop.
Provides an iterator that allows for simple traversing over an dataSource's IndexPath's – including support for a header and footer per section.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public struct IndexPathIterator: IteratorProtocol { | |
public let indexPaths: [IndexPath] | |
private var index: Array<IndexPath>.Index | |
/// Creates a new iterator for the specified indexPaths | |
/// | |
/// - Parameter indexPaths: The indexPaths to iterate over | |
public init(indexPaths: Set<IndexPath>) { | |
self.indexPaths = indexPaths.sorted() | |
self.index = self.indexPaths.startIndex | |
} | |
/// Returns the next element. If there are no more elements, this returns nil. | |
/// | |
/// - Returns: Returns the next element. If the collection is empty, this returns nil | |
public mutating func next() -> Array<IndexPath>.Element? { | |
guard !indexPaths.isEmpty, index != indexPaths.endIndex else { return nil } | |
let result = indexPaths[index] | |
indexPaths.formIndex(after: &index) | |
return result | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public extension IndexPath { | |
enum Kind: Int { | |
case header | |
case footer | |
case item | |
} | |
struct KindMask: RawRepresentable, OptionSet { | |
public let rawValue: Int | |
public init(rawValue: Int) { | |
self.rawValue = rawValue | |
} | |
public static let header = KindMask(rawValue: 1 << Kind.header.rawValue) | |
public static let footer = KindMask(rawValue: 1 << Kind.footer.rawValue) | |
public static let item = KindMask(rawValue: 1 << Kind.item.rawValue) | |
public func contains(_ member: Kind) -> Bool { | |
if member == .header && contains(KindMask.header) { return true } | |
if member == .footer && contains(KindMask.footer) { return true } | |
if member == .item && contains(KindMask.item) { return true } | |
return false | |
} | |
} | |
init(kind: Kind, item: Int, section: Int) { | |
switch kind { | |
case .header: | |
self = [section, -1, 0] | |
case .footer: | |
self = [section, item, 1] | |
case .item: | |
self = IndexPath(item: item, section: section) | |
} | |
} | |
var kind: Kind { | |
guard count == 3 else { return .item } | |
return self[2] == 0 ? .header : .footer | |
} | |
var section: Int { | |
return self[0] | |
} | |
var item: Int { | |
return self[1] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
public extension Collection where Element == IndexPath { | |
/// Returns indexPaths of the specified kinds, that are in the given section | |
/// | |
/// - Parameters: | |
/// - kinds: The kinds to match against | |
/// - section: The section to match against | |
/// - Returns: An array of indexPaths, empty if no matches | |
func filter(include kinds: IndexPath.KindMask, inSections sections: Int...) -> [SubSequence.Element] { | |
return filter { sections.contains($0.section) && kinds.contains($0.kind) } | |
} | |
/// Returns indexPaths of the specified kinds, that are in the given section | |
/// | |
/// - Parameters: | |
/// - kinds: The kinds to match against | |
/// - section: The section to match against | |
/// - Returns: An array of indexPaths, empty if no matches | |
func filter(include kinds: IndexPath.KindMask, inSections sections: [Int]) -> [SubSequence.Element] { | |
return filter { sections.contains($0.section) && kinds.contains($0.kind) } | |
} | |
/// Returns indexPaths of the specified kinds, that are in the specified sections | |
/// | |
/// - Parameters: | |
/// - kinds: The kinds to match against | |
/// - range: The range of sections to match against | |
/// - Returns: An array of indexPaths, empty if no matches | |
func filter(include kinds: IndexPath.KindMask, inSections range: Range<Int>) -> [SubSequence.Element] { | |
return filter { range.contains($0.section) && kinds.contains($0.kind) } | |
} | |
/// Returns indexPaths of the specified kinds, that are in the specified sections | |
/// | |
/// - Parameters: | |
/// - kinds: The kinds to match against | |
/// - range: The range of sections to match against | |
/// - Returns: An array of indexPaths, empty if no matches | |
func filter(include kinds: IndexPath.KindMask, inSections range: ClosedRange<Int>) -> [SubSequence.Element] { | |
return filter { range.contains($0.section) && kinds.contains($0.kind) } | |
} | |
/// Returns indexPaths of the specified kinds, in any section | |
/// | |
/// - Parameter kinds: The kinds to match against | |
/// - Returns: an array of indexPaths, empty if no matches | |
func filter(include kinds: IndexPath.KindMask) -> [SubSequence.Element] { | |
return filter { kinds.contains($0.kind) } | |
} | |
/// Returns all header indexPaths only | |
var headers: [SubSequence.Element] { | |
return filter(include: .header) | |
} | |
/// Returns all footer indexPaths only | |
var footers: [SubSequence.Element] { | |
return filter(include: .footer) | |
} | |
/// Returns all item indexPaths only | |
var items: [SubSequence.Element] { | |
return filter(include: .item) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public extension Set where Element == IndexPath { | |
init(from view: UICollectionView) { | |
var indexPaths: Set<IndexPath> = [] | |
for section in 0..<(view.dataSource?.numberOfSections?(in: view) ?? 0) { | |
indexPaths.insert(IndexPath(kind: .header, item: -1, section: section)) | |
let itemCount = view.dataSource?.collectionView(view, numberOfItemsInSection: section) ?? 0 | |
for item in 0..<itemCount { | |
indexPaths.insert(IndexPath(item: item, section: section)) | |
} | |
indexPaths.insert(IndexPath(kind: .footer, item: itemCount, section: section)) | |
} | |
self.init(indexPaths) | |
} | |
init(from view: UITableView) { | |
var indexPaths: Set<IndexPath> = [] | |
for section in 0..<(view.dataSource?.numberOfSections?(in: view) ?? 0) { | |
indexPaths.insert(IndexPath(kind: .header, item: -1, section: section)) | |
let itemCount = view.dataSource?.tableView(view, numberOfRowsInSection: section) ?? 0 | |
for item in 0..<itemCount { | |
indexPaths.insert(IndexPath(item: item, section: section)) | |
} | |
indexPaths.insert(IndexPath(kind: .footer, item: itemCount, section: section)) | |
} | |
self.init(indexPaths) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example: