jsdw_ios/Pods/RxDataSources/Sources/RxDataSources/RxCollectionViewSectionedAn...

102 lines
4.1 KiB
Swift

//
// 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