diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index fe97e5d84f..71973f8633 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -98,7 +98,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; ASCollectionDataController *_dataController; ASRangeController *_rangeController; ASCollectionViewLayoutController *_layoutController; - id _defaultLayoutInspector; + ASCollectionViewFlowLayoutInspector *_flowLayoutInspector; NSMutableSet *_cellsForVisibilityUpdates; id _layoutFacilitator; @@ -246,19 +246,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; // and should not trigger a relayout. _ignoreMaxSizeChange = CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, CGSizeZero); + // Register the default layout inspector delegate for flow layouts only, custom layouts + // will need to roll their own ASCollectionViewLayoutInspecting implementation and set a layout delegate if ([layout asdk_isFlowLayout]) { - // Register the default layout inspector delegate for flow layouts only - UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout; - ASDisplayNodeAssertNotNil(layout, @"Collection view layout must be a flow layout to use the built-in inspector"); - _defaultLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:self flowLayout:layout]; - } else { - // Custom layouts will need to roll their own ASCollectionViewLayoutInspecting implementation and set a layout - // delegate. In the meantime ASDK provides a custom layout inspector that does not provide any implementation - // and asserts for methods that should be implemented in the - _defaultLayoutInspector = [[ASCollectionViewCustomLayoutInspector alloc] init]; + _layoutInspector = [self flowLayoutInspector]; } - _layoutInspector = _defaultLayoutInspector; - _layoutFacilitator = layoutFacilitator; _proxyDelegate = [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self]; @@ -285,6 +277,19 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; [self setAsyncDataSource:nil]; } +/** + * A layout inspector implementation specific for the sizing behavior of UICollectionViewFlowLayouts + */ +- (ASCollectionViewFlowLayoutInspector *)flowLayoutInspector +{ + if (_flowLayoutInspector == nil) { + UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout; + ASDisplayNodeAssertNotNil(layout, @"Collection view layout must be a flow layout to use the built-in inspector"); + _flowLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:self flowLayout:layout]; + } + return _flowLayoutInspector; +} + #pragma mark - #pragma mark Overrides. @@ -404,9 +409,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; super.delegate = (id)_proxyDelegate; - if ([_layoutInspector respondsToSelector:@selector(didChangeCollectionViewDelegate:)]) { - [_layoutInspector didChangeCollectionViewDelegate:asyncDelegate]; - } + [_layoutInspector didChangeCollectionViewDelegate:asyncDelegate]; } - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType @@ -888,21 +891,28 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (ASSizeRange)dataController:(ASDataController *)dataController constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath { - ASSizeRange constrainedSize = [_layoutInspector collectionView:self constrainedSizeForNodeAtIndexPath:indexPath]; + ASSizeRange constrainedSize = kInvalidSizeRange; + if (_layoutInspector) { + constrainedSize = [_layoutInspector collectionView:self constrainedSizeForNodeAtIndexPath:indexPath]; + } + if (!ASSizeRangeEqualToSizeRange(constrainedSize, kInvalidSizeRange)) { return constrainedSize; } - CGSize maxSize = _maxSizeForNodesConstrainedSize; - if (CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, CGSizeZero)) { - maxSize = self.bounds.size; - } - if (ASScrollDirectionContainsHorizontalDirection([self scrollableDirections])) { - maxSize.width = FLT_MAX; + // TODO: Move this logic into the flow layout inspector. Create a simple inspector for non-flow layouts that don't + // implement a custom inspector. + if (_asyncDataSourceFlags.asyncDataSourceConstrainedSizeForNode) { + constrainedSize = [_asyncDataSource collectionView:self constrainedSizeForNodeAtIndexPath:indexPath]; } else { - maxSize.height = FLT_MAX; + CGSize maxSize = CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, CGSizeZero) ? self.bounds.size : _maxSizeForNodesConstrainedSize; + if (ASScrollDirectionContainsHorizontalDirection([self scrollableDirections])) { + maxSize.width = FLT_MAX; + } else { + maxSize.height = FLT_MAX; + } + constrainedSize = ASSizeRangeMake(CGSizeZero, maxSize); } - constrainedSize = ASSizeRangeMake(CGSizeZero, maxSize); return constrainedSize; } @@ -964,16 +974,19 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + ASDisplayNodeAssert(_layoutInspector != nil, @"To support supplementary nodes in ASCollectionView, it must have a layoutDelegate for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)"); return [_layoutInspector collectionView:self constrainedSizeForSupplementaryNodeOfKind:kind atIndexPath:indexPath]; } - (NSUInteger)dataController:(ASCollectionDataController *)dataController supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section { + ASDisplayNodeAssert(_layoutInspector != nil, @"To support supplementary nodes in ASCollectionView, it must have a layoutDelegate for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)"); return [_layoutInspector collectionView:self supplementaryNodesOfKind:kind inSection:section]; } - (NSUInteger)dataController:(ASCollectionDataController *)dataController numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind; { + ASDisplayNodeAssert(_layoutInspector != nil, @"To support supplementary nodes in ASCollectionView, it must have a layoutDelegate for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)"); return [_layoutInspector collectionView:self numberOfSectionsForSupplementaryNodeOfKind:kind]; } diff --git a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h index 28fcafa1ab..cd640c3e2a 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h +++ b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h @@ -47,17 +47,6 @@ @end -/** - * Simple "Null Object" inspector for non-flow layouts that does not implement a custom inspector, provides a zero - * constrained size and throws an exception if methods are called from - */ -@interface ASCollectionViewCustomLayoutInspector : NSObject - -@end - -/** - * A layout inspector implementation specific for the sizing behavior of UICollectionViewFlowLayouts - */ @interface ASCollectionViewFlowLayoutInspector : NSObject @property (nonatomic, weak) UICollectionViewFlowLayout *layout; diff --git a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m index 50f5aa5b35..3fe377f3a3 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m +++ b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m @@ -13,35 +13,6 @@ #import "ASAssert.h" #import "ASEqualityHelpers.h" - - -@implementation ASCollectionViewCustomLayoutInspector - -- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath -{ - return ASSizeRangeMake(CGSizeZero, CGSizeZero); -} - -- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath -{ - ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutDelegate for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)"); - return ASSizeRangeMake(CGSizeZero, CGSizeZero); -} - -- (NSUInteger)collectionView:(ASCollectionView *)collectionView numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind -{ - ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutDelegate for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)"); - return 0; -} - -- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section -{ - ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutDelegate for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)"); - return 0; -} - -@end - @implementation ASCollectionViewFlowLayoutInspector { BOOL _delegateImplementsReferenceSizeForHeader; BOOL _delegateImplementsReferenceSizeForFooter; @@ -79,11 +50,8 @@ - (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath { - if ([collectionView.asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)]) { - return [collectionView.asyncDataSource collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath]; - } else { - return ASSizeRangeMake(_layout.itemSize, _layout.itemSize); - } + // TODO: Provide constrained size for flow layout item nodes + return ASSizeRangeMake(CGSizeZero, CGSizeZero); } - (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath diff --git a/AsyncDisplayKitTests/ASCollectionViewTests.m b/AsyncDisplayKitTests/ASCollectionViewTests.m index e08d33a1cf..8c7f258a5a 100644 --- a/AsyncDisplayKitTests/ASCollectionViewTests.m +++ b/AsyncDisplayKitTests/ASCollectionViewTests.m @@ -108,10 +108,7 @@ { UICollectionViewLayout *layout = [[UICollectionViewLayout alloc] init]; ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; - XCTAssert(collectionView.layoutInspector != nil, @"should automatically set a layout delegate for custom layouts"); - XCTAssert([collectionView.layoutInspector isKindOfClass:[ASCollectionViewCustomLayoutInspector class]], @"should have a internal custom layout inspector by default"); - XCTAssert(ASSizeRangeEqualToSizeRange([collectionView.layoutInspector collectionView:collectionView constrainedSizeForNodeAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]], ASSizeRangeMake(CGSizeZero, CGSizeZero)), @"should return a zero constrainted size range in internal custom layout inspector"); - XCTAssertThrows([collectionView.layoutInspector collectionView:collectionView supplementaryNodesOfKind:UICollectionElementKindSectionHeader inSection:0], @"should throw an exception for methods"); + XCTAssert(collectionView.layoutInspector == nil, @"should not set a layout delegate for custom layouts"); } - (void)testThatRegisteringASupplementaryNodeStoresItForIntrospection