diff --git a/CollectionKit.xcodeproj/project.pbxproj b/CollectionKit.xcodeproj/project.pbxproj index edf99ae..55d1e2d 100644 --- a/CollectionKit.xcodeproj/project.pbxproj +++ b/CollectionKit.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 0E3258451F5E23B000D455F8 /* FlowLayoutSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3258441F5E23B000D455F8 /* FlowLayoutSpec.swift */; }; + A3066AAD2176997900467E3C /* BasicProvider+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3066AAC2176997800467E3C /* BasicProvider+Convenience.swift */; }; + A3066AAF2176997F00467E3C /* ComposedHeaderProvider+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3066AAE2176997F00467E3C /* ComposedHeaderProvider+Convenience.swift */; }; A3299F342064ED690075A137 /* VisibleFrameInsetLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3299F332064ED690075A137 /* VisibleFrameInsetLayout.swift */; }; A363C56520C7EA44009A885F /* ComposedViewSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = A363C56420C7EA44009A885F /* ComposedViewSource.swift */; }; A363C56620C7EA66009A885F /* AnyViewSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = A363C56220C7EA2E009A885F /* AnyViewSource.swift */; }; @@ -74,6 +76,8 @@ 0E3258441F5E23B000D455F8 /* FlowLayoutSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlowLayoutSpec.swift; sourceTree = ""; }; 18407FD826F3703406A838D4 /* Pods_CollectionKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CollectionKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 571F2E4FA7747B7E5CAC5A2D /* Pods-CollectionKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CollectionKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CollectionKitTests/Pods-CollectionKitTests.debug.xcconfig"; sourceTree = ""; }; + A3066AAC2176997800467E3C /* BasicProvider+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BasicProvider+Convenience.swift"; sourceTree = ""; }; + A3066AAE2176997F00467E3C /* ComposedHeaderProvider+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ComposedHeaderProvider+Convenience.swift"; sourceTree = ""; }; A3299F332064ED690075A137 /* VisibleFrameInsetLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleFrameInsetLayout.swift; sourceTree = ""; }; A32B59BD213C063400DED8B4 /* CollectionKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CollectionKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A32B59BE213C063400DED8B4 /* CollectionKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CollectionKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -279,8 +283,10 @@ isa = PBXGroup; children = ( B148237A1F1E87F60007A7E2 /* BasicProvider.swift */, + A3066AAC2176997800467E3C /* BasicProvider+Convenience.swift */, B1E861F81F21520200621BA0 /* ComposedProvider.swift */, A363C56D20CBD55B009A885F /* ComposedHeaderProvider.swift */, + A3066AAE2176997F00467E3C /* ComposedHeaderProvider+Convenience.swift */, A363C56B20CACA89009A885F /* FlattenedProvider.swift */, B144CE091F437A6B0073CF4E /* EmptyCollectionProvider.swift */, ); @@ -526,6 +532,7 @@ B1688A2D1F25632900C229BD /* SpaceProvider.swift in Sources */, A363C56520C7EA44009A885F /* ComposedViewSource.swift in Sources */, B1B7B0611E7DAD2700F2483E /* Util.swift in Sources */, + A3066AAD2176997900467E3C /* BasicProvider+Convenience.swift in Sources */, B144CE0A1F437A6B0073CF4E /* EmptyCollectionProvider.swift in Sources */, B144CE061F437A1D0073CF4E /* RowLayout.swift in Sources */, B19D64C91F23DCA800D02FDB /* CollectionReuseViewManager.swift in Sources */, @@ -546,6 +553,7 @@ B1B7B05F1E7DAD2700F2483E /* CollectionView.swift in Sources */, B157E51A1F6719F0008AEF83 /* SimpleLayout.swift in Sources */, A3299F342064ED690075A137 /* VisibleFrameInsetLayout.swift in Sources */, + A3066AAF2176997F00467E3C /* ComposedHeaderProvider+Convenience.swift in Sources */, B1E861F41F21517400621BA0 /* DataSource.swift in Sources */, A3C76C1F20D10817003082BF /* LayoutableProvider.swift in Sources */, B157E5181F66FEE5008AEF83 /* OverlayLayout.swift in Sources */, diff --git a/CollectionKitTests/CollectionViewSpec.swift b/CollectionKitTests/CollectionViewSpec.swift index cbdf81d..28cdfc8 100644 --- a/CollectionKitTests/CollectionViewSpec.swift +++ b/CollectionKitTests/CollectionViewSpec.swift @@ -21,11 +21,11 @@ class CollectionViewSpec: QuickSpec { dataSource = ArrayDataSource(data: [1, 2, 3, 4]) provider = BasicProvider( dataSource: dataSource, - viewSource: ClosureViewSource(viewUpdater: { (label: UILabel, data: Int, index: Int) in + viewSource: { (label: UILabel, data: Int, index: Int) in label.backgroundColor = .red label.textAlignment = .center label.text = "\(data)" - }), + }, sizeSource: { (index: Int, data: Int, collectionSize: CGSize) -> CGSize in return CGSize(width: 50, height: 50) } @@ -228,10 +228,10 @@ class CollectionViewSpec: QuickSpec { expect((collectionView.cell(at: 1) as! UILabel).text) == "2" provider = BasicProvider( - dataSource: ArrayDataSource(data: [0, 0, 0, 0]), - viewSource: ClosureViewSource(viewUpdater: { (label: UILabel, data: Int, index: Int) in + dataSource: [0, 0, 0, 0], + viewSource: { (label: UILabel, data: Int, index: Int) in label.text = "\(data)" - }), + }, sizeSource: { (index: Int, data: Int, collectionSize: CGSize) -> CGSize in return CGSize(width: 50, height: 50) } @@ -264,10 +264,10 @@ class CollectionViewSpec: QuickSpec { it("handles tap") { var lastTappedIndex: Int = -1 provider = BasicProvider( - dataSource: ArrayDataSource(data: [0, 1, 2, 3]), - viewSource: ClosureViewSource(viewUpdater: { (label: UILabel, data: Int, index: Int) in + dataSource: [0, 1, 2, 3], + viewSource: { (label: UILabel, data: Int, index: Int) in label.text = "\(data)" - }), + }, sizeSource: { (index: Int, data: Int, collectionSize: CGSize) -> CGSize in return CGSize(width: 50, height: 50) }, diff --git a/CollectionKitTests/ComposedProviderSpec.swift b/CollectionKitTests/ComposedProviderSpec.swift index 90e458e..75e02b6 100644 --- a/CollectionKitTests/ComposedProviderSpec.swift +++ b/CollectionKitTests/ComposedProviderSpec.swift @@ -102,9 +102,9 @@ class ComposedProviderSpec: QuickSpec { expect(collectionView.subviews[0].frame.origin) == CGPoint.zero expect(collectionView.subviews[1].frame.origin) == CGPoint(x: 50, y: 0) - provider1.sizeSource = { _, _, _ in + provider1.sizeSource = ClosureSizeSource(sizeSource: { _, _, _ in return CGSize(width: 30, height: 30) - } + }) collectionView.layoutIfNeeded() expect(collectionView.reloadCount) == 1 expect(collectionView.subviews[0].frame.origin) == CGPoint.zero @@ -160,11 +160,11 @@ class ComposedProviderSpec: QuickSpec { let provider2 = SimpleTestProvider(data: ["a", "b"]) let tapProvider = BasicProvider( - dataSource: ArrayDataSource(data: [11, 12]), - viewSource: ClosureViewSource(viewUpdater: { + dataSource: [11, 12], + viewSource: { (label: UILabel, data: Int, index: Int) in label.text = "\(data)" - }), + }, sizeSource: { (index: Int, data: Int, collectionSize: CGSize) -> CGSize in return CGSize(width: 50, height: 50) }, diff --git a/CollectionKitTests/TestUils.swift b/CollectionKitTests/TestUils.swift index 3cc021d..df36119 100644 --- a/CollectionKitTests/TestUils.swift +++ b/CollectionKitTests/TestUils.swift @@ -54,9 +54,9 @@ class SimpleTestProvider: BasicProvider { label.textAlignment = .center label.text = "\(data)" }), - sizeSource: { (index: Int, data: Data, collectionSize: CGSize) -> CGSize in + sizeSource: ClosureSizeSource(sizeSource: { (index: Int, data: Data, collectionSize: CGSize) -> CGSize in return CGSize(width: 50, height: 50) - } + }) ) } diff --git a/Examples/CollectionKitExamples/AnimatorExample/AnimatorExampleViewController.swift b/Examples/CollectionKitExamples/AnimatorExample/AnimatorExampleViewController.swift index b04ef1c..05b1d1f 100644 --- a/Examples/CollectionKitExamples/AnimatorExample/AnimatorExampleViewController.swift +++ b/Examples/CollectionKitExamples/AnimatorExample/AnimatorExampleViewController.swift @@ -24,7 +24,7 @@ class AnimatorExampleViewController: CollectionViewController { let visibleFrameInsets = UIEdgeInsets(top: 0, left: -100, bottom: 0, right: -100) let imageProvider = BasicProvider( - dataSource: ArrayDataSource(data: testImages), + dataSource: testImages, viewSource: ClosureViewSource(viewGenerator: { (data, index) -> UIImageView in let view = UIImageView() view.layer.cornerRadius = 5 @@ -33,7 +33,7 @@ class AnimatorExampleViewController: CollectionViewController { }, viewUpdater: { (view: UIImageView, data: UIImage, at: Int) in view.image = data }), - sizeSource: imageSizeProvider, + sizeSource: UIImageSizeSource(), layout: WaterfallLayout(columns: 2, spacing: 10).transposed().inset(by: bodyInset).insetVisibleFrame(by: visibleFrameInsets), animator: animators[0].1 ) @@ -44,12 +44,12 @@ class AnimatorExampleViewController: CollectionViewController { buttonsCollectionView.showsHorizontalScrollIndicator = false let buttonsProvider = BasicProvider( - dataSource: ArrayDataSource(data: animators), - viewSource: ClosureViewSource(viewUpdater: { (view: SelectionButton, data: (String, Animator), at: Int) in + dataSource: animators, + viewSource: { (view: SelectionButton, data: (String, Animator), at: Int) in view.label.text = data.0 view.label.textColor = imageProvider.animator === data.1 ? .white : .black view.backgroundColor = imageProvider.animator === data.1 ? .lightGray : .white - }), + }, sizeSource: { _, data, maxSize in return CGSize(width: data.0.width(withConstraintedHeight: maxSize.height, font: UIFont.systemFont(ofSize:18)) + 20, height: maxSize.height) }, diff --git a/Examples/CollectionKitExamples/ArticleExample/ArticleExampleViewController.swift b/Examples/CollectionKitExamples/ArticleExample/ArticleExampleViewController.swift index 5c3ccc4..3aa6623 100644 --- a/Examples/CollectionKitExamples/ArticleExample/ArticleExampleViewController.swift +++ b/Examples/CollectionKitExamples/ArticleExample/ArticleExampleViewController.swift @@ -25,11 +25,10 @@ class ArticleExampleViewController: CollectionViewController { collectionView.contentInset = UIEdgeInsets(top: 20, left: 16, bottom: 20, right: 16) provider = BasicProvider( - dataSource: ArrayDataSource(data: articles), - viewSource: ClosureViewSource(viewUpdater: { - (view: ArticleView, data: ArticleData, at: Int) in + dataSource: articles, + viewSource: { (view: ArticleView, data: ArticleData, at: Int) in view.populate(article: data) - }), + }, sizeSource: { (_, view, size) -> CGSize in return CGSize(width: size.width, height: 200) }, diff --git a/Examples/CollectionKitExamples/GridExample/GridViewController.swift b/Examples/CollectionKitExamples/GridExample/GridViewController.swift index 5807954..970a94f 100644 --- a/Examples/CollectionKitExamples/GridExample/GridViewController.swift +++ b/Examples/CollectionKitExamples/GridExample/GridViewController.swift @@ -31,11 +31,11 @@ class GridViewController: CollectionViewController { collectionView.contentInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) provider = BasicProvider( dataSource: dataSource, - viewSource: ClosureViewSource(viewUpdater: { (view: SquareView, data: Int, index: Int) in + viewSource: { (view: SquareView, data: Int, index: Int) in view.backgroundColor = UIColor(hue: CGFloat(index) / CGFloat(kGridSize.width * kGridSize.height), saturation: 0.68, brightness: 0.98, alpha: 1) view.text = "\(data)" - }), + }, layout: layout, animator: WobbleAnimator() ) diff --git a/Examples/CollectionKitExamples/HeaderExample/HeaderExampleViewController.swift b/Examples/CollectionKitExamples/HeaderExample/HeaderExampleViewController.swift index c3107dd..f373dc2 100644 --- a/Examples/CollectionKitExamples/HeaderExample/HeaderExampleViewController.swift +++ b/Examples/CollectionKitExamples/HeaderExample/HeaderExampleViewController.swift @@ -50,13 +50,12 @@ class HeaderExampleViewController: CollectionViewController { } let provider = ComposedHeaderProvider( - headerViewSource: ClosureViewSource( - viewUpdater: { (view: UILabel, data, index) in + headerViewSource: { (view: UILabel, data, index) in view.backgroundColor = UIColor.darkGray view.textColor = .white view.textAlignment = .center view.text = "Header \(data.index)" - }), + }, headerSizeSource: { (index, data, maxSize) -> CGSize in return CGSize(width: maxSize.width, height: 40) }, diff --git a/Examples/CollectionKitExamples/HorizontalGalleryExample/HorizontalGalleryViewController.swift b/Examples/CollectionKitExamples/HorizontalGalleryExample/HorizontalGalleryViewController.swift index a5a0cfc..7f9e7b9 100644 --- a/Examples/CollectionKitExamples/HorizontalGalleryExample/HorizontalGalleryViewController.swift +++ b/Examples/CollectionKitExamples/HorizontalGalleryExample/HorizontalGalleryViewController.swift @@ -9,19 +9,6 @@ import UIKit import CollectionKit -func imageSizeProvider(at: Int, data: UIImage, collectionSize: CGSize) -> CGSize { - var imageSize = data.size - if imageSize.width > collectionSize.width { - imageSize.height /= imageSize.width/collectionSize.width - imageSize.width = collectionSize.width - } - if imageSize.height > collectionSize.height { - imageSize.width /= imageSize.height/collectionSize.height - imageSize.height = collectionSize.height - } - return imageSize -} - class HorizontalGalleryViewController: CollectionViewController { override func viewDidLoad() { super.viewDidLoad() @@ -30,7 +17,7 @@ class HorizontalGalleryViewController: CollectionViewController { let visibleFrameInsets = UIEdgeInsets(top: 0, left: -100, bottom: 0, right: -100) provider = BasicProvider( - dataSource: ArrayDataSource(data: testImages), + dataSource: testImages, viewSource: ClosureViewSource(viewGenerator: { (data, index) -> UIImageView in let view = UIImageView() view.layer.cornerRadius = 5 @@ -39,7 +26,7 @@ class HorizontalGalleryViewController: CollectionViewController { }, viewUpdater: { (view: UIImageView, data: UIImage, at: Int) in view.image = data }), - sizeSource: imageSizeProvider, + sizeSource: UIImageSizeSource(), layout: WaterfallLayout(columns: 2, spacing: 10).transposed().insetVisibleFrame(by: visibleFrameInsets), animator: WobbleAnimator() ) diff --git a/Examples/CollectionKitExamples/ReloadAnimationExample/ReloadAnimationViewController.swift b/Examples/CollectionKitExamples/ReloadAnimationExample/ReloadAnimationViewController.swift index 96dbd63..be042e9 100644 --- a/Examples/CollectionKitExamples/ReloadAnimationExample/ReloadAnimationViewController.swift +++ b/Examples/CollectionKitExamples/ReloadAnimationExample/ReloadAnimationViewController.swift @@ -111,13 +111,13 @@ class ReloadAnimationViewController: CollectionViewController { provider = BasicProvider( dataSource: dataSource, - viewSource: ClosureViewSource(viewUpdater: { (view: SquareView, data: Int, index: Int) in + viewSource: { (view: SquareView, data: Int, index: Int) in view.backgroundColor = UIColor(hue: CGFloat(data) / 30, saturation: 0.68, brightness: 0.98, alpha: 1) view.text = "\(data)" - }), + }, sizeSource: { (index, data, _) in return CGSize(width: 80, height: 80) }, diff --git a/Examples/CollectionKitExamples/ReloadDataExample/ReloadDataViewController.swift b/Examples/CollectionKitExamples/ReloadDataExample/ReloadDataViewController.swift index cb39a28..1dc51b8 100644 --- a/Examples/CollectionKitExamples/ReloadDataExample/ReloadDataViewController.swift +++ b/Examples/CollectionKitExamples/ReloadDataExample/ReloadDataViewController.swift @@ -38,13 +38,13 @@ class ReloadDataViewController: CollectionViewController { provider = BasicProvider( dataSource: dataSource, - viewSource: ClosureViewSource(viewUpdater: { (view: SquareView, data: Int, index: Int) in + viewSource: { (view: SquareView, data: Int, index: Int) in view.backgroundColor = UIColor(hue: CGFloat(data) / 30, saturation: 0.68, brightness: 0.98, alpha: 1) view.text = "\(data)" - }), + }, sizeSource: { (index, data, _) in return CGSize(width: 80, height: data % 3 == 0 ? 120 : 80) }, diff --git a/Examples/CollectionKitExamples/ViewController.swift b/Examples/CollectionKitExamples/ViewController.swift index 947aa80..8a20ea9 100644 --- a/Examples/CollectionKitExamples/ViewController.swift +++ b/Examples/CollectionKitExamples/ViewController.swift @@ -33,11 +33,10 @@ class ViewController: CollectionViewController { super.viewDidLoad() let examplesSection = BasicProvider( - dataSource: ArrayDataSource(data: examples), - viewSource: ClosureViewSource(viewUpdater: { - (view: ExampleView, data: (String, UIViewController.Type), at: Int) in + dataSource: examples, + viewSource: { (view: ExampleView, data: (String, UIViewController.Type), at: Int) in view.populate(title: data.0, contentViewControllerType: data.1) - }), + }, sizeSource: { (_, _, size) -> CGSize in return CGSize(width: size.width, height: max(360, UIScreen.main.bounds.height * 0.7)) }, diff --git a/Sources/Layout/LayoutContext.swift b/Sources/Layout/LayoutContext.swift index ad1b553..35fbc42 100644 --- a/Sources/Layout/LayoutContext.swift +++ b/Sources/Layout/LayoutContext.swift @@ -13,5 +13,5 @@ public protocol LayoutContext { var numberOfItems: Int { get } func data(at: Int) -> Any func identifier(at: Int) -> String - func size(at: Int, collectionSize: CGSize) -> CGSize + func size(at index: Int, collectionSize: CGSize) -> CGSize } diff --git a/Sources/Other/Deprecated.swift b/Sources/Other/Deprecated.swift index aa2705e..1ac7666 100644 --- a/Sources/Other/Deprecated.swift +++ b/Sources/Other/Deprecated.swift @@ -78,7 +78,7 @@ extension BasicProvider { dataProvider: DataSource, viewProvider: ViewSource, layout: Layout = FlowLayout(), - sizeProvider: @escaping SizeSource = defaultSizeSource, + sizeProvider: SizeSource = SizeSource(), presenter: Animator? = nil, willReloadHandler: (() -> Void)? = nil, didReloadHandler: (() -> Void)? = nil, @@ -98,7 +98,7 @@ extension BasicProvider { viewGenerator: ((Data, Int) -> View)? = nil, viewUpdater: @escaping (View, Data, Int) -> Void, layout: Layout = FlowLayout(), - sizeProvider: @escaping SizeSource = defaultSizeSource, + sizeProvider: SizeSource = SizeSource(), presenter: Animator? = nil, willReloadHandler: (() -> Void)? = nil, didReloadHandler: (() -> Void)? = nil, @@ -118,7 +118,7 @@ extension BasicProvider { viewGenerator: ((Data, Int) -> View)? = nil, viewUpdater: @escaping (View, Data, Int) -> Void, layout: Layout = FlowLayout(), - sizeProvider: @escaping SizeSource = defaultSizeSource, + sizeProvider: SizeSource = SizeSource(), presenter: Animator? = nil, willReloadHandler: (() -> Void)? = nil, didReloadHandler: (() -> Void)? = nil, diff --git a/Sources/Other/SizeSource.swift b/Sources/Other/SizeSource.swift index be1fb22..60e00d5 100644 --- a/Sources/Other/SizeSource.swift +++ b/Sources/Other/SizeSource.swift @@ -8,8 +8,42 @@ import UIKit -public typealias SizeSource = (Int, Data, CGSize) -> CGSize +public typealias ClosureSizeSourceFn = (Int, Data, CGSize) -> CGSize -public func defaultSizeSource(at: Int, data: Data, collectionSize: CGSize) -> CGSize { - return collectionSize +open class SizeSource { + + public init() {} + + // override point for subclass + open func size(at index: Int, data: Data, collectionSize: CGSize) -> CGSize { + return collectionSize + } +} + +open class UIImageSizeSource: SizeSource { + open override func size(at index: Int, data: UIImage, collectionSize: CGSize) -> CGSize { + var imageSize = data.size + if imageSize.width > collectionSize.width { + imageSize.height /= imageSize.width / collectionSize.width + imageSize.width = collectionSize.width + } + if imageSize.height > collectionSize.height { + imageSize.width /= imageSize.height / collectionSize.height + imageSize.height = collectionSize.height + } + return imageSize + } +} + +open class ClosureSizeSource: SizeSource { + open var sizeSource: ClosureSizeSourceFn + + public init(sizeSource: @escaping ClosureSizeSourceFn) { + self.sizeSource = sizeSource + super.init() + } + + open override func size(at index: Int, data: Data, collectionSize: CGSize) -> CGSize { + return sizeSource(index, data, collectionSize) + } } diff --git a/Sources/Provider/BasicProvider+Convenience.swift b/Sources/Provider/BasicProvider+Convenience.swift new file mode 100644 index 0000000..dfa2600 --- /dev/null +++ b/Sources/Provider/BasicProvider+Convenience.swift @@ -0,0 +1,162 @@ +// +// BasicProvider+Convenience.swift +// CollectionKit +// +// Created by Luke Zhao on 2018-10-15. +// + +extension BasicProvider { + public convenience init(identifier: String? = nil, + dataSource: DataSource, + viewSource: @escaping ViewUpdaterFn, + sizeSource: SizeSource, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: dataSource, + viewSource: ClosureViewSource(viewUpdater: viewSource), + sizeSource: sizeSource, + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: DataSource, + viewSource: ViewSource, + sizeSource: @escaping ClosureSizeSourceFn, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: dataSource, + viewSource: viewSource, + sizeSource: ClosureSizeSource(sizeSource: sizeSource), + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: DataSource, + viewSource: @escaping ViewUpdaterFn, + sizeSource: @escaping ClosureSizeSourceFn, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: dataSource, + viewSource: ClosureViewSource(viewUpdater: viewSource), + sizeSource: ClosureSizeSource(sizeSource: sizeSource), + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: [Data], + viewSource: ViewSource, + sizeSource: SizeSource, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: ArrayDataSource(data: dataSource), + viewSource: viewSource, + sizeSource: sizeSource, + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: [Data], + viewSource: @escaping ViewUpdaterFn, + sizeSource: SizeSource, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: ArrayDataSource(data: dataSource), + viewSource: ClosureViewSource(viewUpdater: viewSource), + sizeSource: sizeSource, + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: [Data], + viewSource: ViewSource, + sizeSource: @escaping ClosureSizeSourceFn, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: ArrayDataSource(data: dataSource), + viewSource: viewSource, + sizeSource: ClosureSizeSource(sizeSource: sizeSource), + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: [Data], + viewSource: @escaping ViewUpdaterFn, + sizeSource: @escaping ClosureSizeSourceFn, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: ArrayDataSource(data: dataSource), + viewSource: ClosureViewSource(viewUpdater: viewSource), + sizeSource: ClosureSizeSource(sizeSource: sizeSource), + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: [Data], + viewSource: @escaping ViewUpdaterFn, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: ArrayDataSource(data: dataSource), + viewSource: ClosureViewSource(viewUpdater: viewSource), + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: [Data], + viewSource: ViewSource, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: ArrayDataSource(data: dataSource), + viewSource: viewSource, + layout: layout, + animator: animator, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + dataSource: DataSource, + viewSource: @escaping ViewUpdaterFn, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + dataSource: dataSource, + viewSource: ClosureViewSource(viewUpdater: viewSource), + layout: layout, + animator: animator, + tapHandler: tapHandler) + } +} diff --git a/Sources/Provider/BasicProvider.swift b/Sources/Provider/BasicProvider.swift index a984d03..027334d 100644 --- a/Sources/Provider/BasicProvider.swift +++ b/Sources/Provider/BasicProvider.swift @@ -37,7 +37,7 @@ open class BasicProvider: ItemProvider, LayoutableProvider, public init(identifier: String? = nil, dataSource: DataSource, viewSource: ViewSource, - sizeSource: @escaping SizeSource = defaultSizeSource, + sizeSource: SizeSource = SizeSource(), layout: Layout = FlowLayout(), animator: Animator? = nil, tapHandler: TapHandler? = nil) { @@ -95,7 +95,7 @@ struct BasicProviderLayoutContext: LayoutContext { func identifier(at: Int) -> String { return dataSource.identifier(at: at) } - func size(at: Int, collectionSize: CGSize) -> CGSize { - return sizeSource(at, dataSource.data(at: at), collectionSize) + func size(at index: Int, collectionSize: CGSize) -> CGSize { + return sizeSource.size(at: index, data: dataSource.data(at: index), collectionSize: collectionSize) } } diff --git a/Sources/Provider/ComposedHeaderProvider+Convenience.swift b/Sources/Provider/ComposedHeaderProvider+Convenience.swift new file mode 100644 index 0000000..1ef2f6f --- /dev/null +++ b/Sources/Provider/ComposedHeaderProvider+Convenience.swift @@ -0,0 +1,56 @@ +// +// ComposedHeaderProvider+Convenience.swift +// CollectionKit +// +// Created by Luke Zhao on 2018-10-15. +// + +extension ComposedHeaderProvider { + public convenience init(identifier: String? = nil, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + headerViewSource: @escaping ViewUpdaterFn, + headerSizeSource: @escaping ClosureSizeSourceFn, + sections: [Provider] = [], + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + layout: layout, + animator: animator, + headerViewSource: ClosureViewSource(viewUpdater: headerViewSource), + headerSizeSource: ClosureSizeSource(sizeSource: headerSizeSource), + sections: sections, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + headerViewSource: HeaderViewSource, + headerSizeSource: @escaping ClosureSizeSourceFn, + sections: [Provider] = [], + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + layout: layout, + animator: animator, + headerViewSource: headerViewSource, + headerSizeSource: ClosureSizeSource(sizeSource: headerSizeSource), + sections: sections, + tapHandler: tapHandler) + } + + public convenience init(identifier: String? = nil, + layout: Layout = FlowLayout(), + animator: Animator? = nil, + headerViewSource: @escaping ViewUpdaterFn, + headerSizeSource: HeaderSizeSource, + sections: [Provider] = [], + tapHandler: TapHandler? = nil) { + self.init(identifier: identifier, + layout: layout, + animator: animator, + headerViewSource: ClosureViewSource(viewUpdater: headerViewSource), + headerSizeSource: headerSizeSource, + sections: sections, + tapHandler: tapHandler) + } +} diff --git a/Sources/Provider/ComposedHeaderProvider.swift b/Sources/Provider/ComposedHeaderProvider.swift index 43c3740..71bc906 100644 --- a/Sources/Provider/ComposedHeaderProvider.swift +++ b/Sources/Provider/ComposedHeaderProvider.swift @@ -73,7 +73,7 @@ open class ComposedHeaderProvider: layout: Layout = FlowLayout(), animator: Animator? = nil, headerViewSource: HeaderViewSource, - headerSizeSource: @escaping HeaderSizeSource, + headerSizeSource: HeaderSizeSource, sections: [Provider] = [], tapHandler: TapHandler? = nil) { self.animator = animator @@ -182,12 +182,14 @@ open class ComposedHeaderProvider: return sectionIdentifier } } - func size(at: Int, collectionSize: CGSize) -> CGSize { - if at % 2 == 0 { - return headerSizeSource(at / 2, data(at: at) as! HeaderData, collectionSize) + func size(at index: Int, collectionSize: CGSize) -> CGSize { + if index % 2 == 0 { + return headerSizeSource.size(at: index / 2, + data: data(at: index) as! HeaderData, + collectionSize: collectionSize) } else { - sections[at / 2].layout(collectionSize: collectionSize) - return sections[at / 2].contentSize + sections[index / 2].layout(collectionSize: collectionSize) + return sections[index / 2].contentSize } } } diff --git a/Sources/ViewSource/ClosureViewSource.swift b/Sources/ViewSource/ClosureViewSource.swift index c7f5758..5222894 100644 --- a/Sources/ViewSource/ClosureViewSource.swift +++ b/Sources/ViewSource/ClosureViewSource.swift @@ -8,11 +8,15 @@ import UIKit +public typealias ViewUpdaterFn = (View, Data, Int) -> Void +public typealias ViewGeneratorFn = (Data, Int) -> View + public class ClosureViewSource: ViewSource where View: UIView { - public var viewUpdater: (View, Data, Int) -> Void - public var viewGenerator: ((Data, Int) -> View)? + public var viewGenerator: ViewGeneratorFn? + public var viewUpdater: ViewUpdaterFn - public init(viewGenerator: ((Data, Int) -> View)? = nil, viewUpdater: @escaping (View, Data, Int) -> Void) { + public init(viewGenerator: ViewGeneratorFn? = nil, + viewUpdater: @escaping ViewUpdaterFn) { self.viewGenerator = viewGenerator self.viewUpdater = viewUpdater super.init()