123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- //
- // RxCollectionViewSectionedAnimatedDataSource.swift
- // RxExample
- //
- // Created by Krunoslav Zaher on 7/2/15.
- // Copyright © 2015 Krunoslav Zaher. All rights reserved.
- //
- #if os(iOS) || os(tvOS)
- import Foundation
- import UIKit
- #if !RX_NO_MODULE
- import RxSwift
- import RxCocoa
- #endif
- import Differentiator
- open class RxCollectionViewSectionedAnimatedDataSource<Section: AnimatableSectionModelType>
- : CollectionViewSectionedDataSource<Section>
- , RxCollectionViewDataSourceType {
- public typealias Element = [Section]
- public typealias DecideViewTransition = (CollectionViewSectionedDataSource<Section>, UICollectionView, [Changeset<Section>]) -> ViewTransition
- // animation configuration
- public var animationConfiguration: AnimationConfiguration
- /// Calculates view transition depending on type of changes
- public var decideViewTransition: DecideViewTransition
- public init(
- animationConfiguration: AnimationConfiguration = AnimationConfiguration(),
- decideViewTransition: @escaping DecideViewTransition = { _, _, _ in .animated },
- configureCell: @escaping ConfigureCell,
- configureSupplementaryView: ConfigureSupplementaryView? = nil,
- moveItem: @escaping MoveItem = { _, _, _ in () },
- canMoveItemAtIndexPath: @escaping CanMoveItemAtIndexPath = { _, _ in false }
- ) {
- self.animationConfiguration = animationConfiguration
- self.decideViewTransition = decideViewTransition
- super.init(
- configureCell: configureCell,
- configureSupplementaryView: configureSupplementaryView,
- moveItem: moveItem,
- canMoveItemAtIndexPath: canMoveItemAtIndexPath
- )
- }
-
- // there is no longer limitation to load initial sections with reloadData
- // but it is kept as a feature everyone got used to
- var dataSet = false
- open func collectionView(_ collectionView: UICollectionView, observedEvent: Event<Element>) {
- Binder(self) { dataSource, newSections in
- #if DEBUG
- dataSource._dataSourceBound = true
- #endif
- if !dataSource.dataSet {
- dataSource.dataSet = true
- dataSource.setSections(newSections)
- collectionView.reloadData()
- }
- else {
- // if view is not in view hierarchy, performing batch updates will crash the app
- if collectionView.window == nil {
- dataSource.setSections(newSections)
- collectionView.reloadData()
- return
- }
- let oldSections = dataSource.sectionModels
- do {
- let differences = try Diff.differencesForSectionedView(initialSections: oldSections, finalSections: newSections)
-
- switch dataSource.decideViewTransition(dataSource, collectionView, differences) {
- case .animated:
- // each difference must be run in a separate 'performBatchUpdates', otherwise it crashes.
- // this is a limitation of Diff tool
- for difference in differences {
- let updateBlock = {
- // sections must be set within updateBlock in 'performBatchUpdates'
- dataSource.setSections(difference.finalSections)
- collectionView.batchUpdates(difference, animationConfiguration: dataSource.animationConfiguration)
- }
- collectionView.performBatchUpdates(updateBlock, completion: nil)
- }
-
- case .reload:
- dataSource.setSections(newSections)
- collectionView.reloadData()
- return
- }
- }
- catch let e {
- rxDebugFatalError(e)
- dataSource.setSections(newSections)
- collectionView.reloadData()
- }
- }
- }.on(observedEvent)
- }
- }
- #endif
|