[ASCollectionView / ASPagerNode] Move constrainedSizeForNodeAtIndexPath from the DataSource to the Delegate (#2065)

* Move constrainedSizeForNodeAtIndexPath from the DataSource to the Delegate in ASCollectionView and ASPagerNode

* Fix ASPagerNode declaration of dataSource and delegate

As ASPagerDataSource does not inherit from ASCollectionDataSource it's not possible to declare it as property.

* Update comment
This commit is contained in:
Michael Schneider
2016-08-12 15:37:23 -07:00
committed by Adlai Holler
parent 2c9e51e8f7
commit 93be894e0c
8 changed files with 74 additions and 50 deletions

View File

@@ -400,17 +400,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
/**
* Provides the constrained size range for measuring the node at the index path.
*
* @param collectionView The sender.
*
* @param indexPath The index path of the node.
*
* @returns A constrained size range for layout the node at this index path.
*/
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
/**
* Indicator to lock the data source for data fetching in async mode.
* We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistency or exception
@@ -442,6 +431,17 @@ NS_ASSUME_NONNULL_BEGIN
@optional
/**
* Provides the constrained size range for measuring the node at the index path.
*
* @param collectionView The sender.
*
* @param indexPath The index path of the node.
*
* @returns A constrained size range for layout the node at this index path.
*/
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
/**
* Informs the delegate that the collection view will add the node
* at the given index path to the view hierarchy.

View File

@@ -151,11 +151,9 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
} _asyncDelegateFlags;
struct {
unsigned int asyncDataSourceConstrainedSizeForNode:1;
unsigned int asyncDataSourceNodeForItemAtIndexPath:1;
unsigned int asyncDataSourceNodeBlockForItemAtIndexPath:1;
unsigned int asyncDataSourceNumberOfSectionsInCollectionView:1;
unsigned int asyncDataSourceCollectionViewConstrainedSizeForNodeAtIndexPath:1;
} _asyncDataSourceFlags;
struct {
@@ -354,11 +352,9 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
_asyncDataSource = asyncDataSource;
_proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
_asyncDataSourceFlags.asyncDataSourceConstrainedSizeForNode = [_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
_asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeForItemAtIndexPath:)];
_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeBlockForItemAtIndexPath:)];
_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInCollectionView = [_asyncDataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)];
_asyncDataSourceFlags.asyncDataSourceCollectionViewConstrainedSizeForNodeAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
// Data-source must implement collectionView:nodeForItemAtIndexPath: or collectionView:nodeBlockForItemAtIndexPath:
ASDisplayNodeAssertTrue(_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath || _asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath);

View File

@@ -16,6 +16,8 @@
@class ASPagerNode;
@class ASPagerFlowLayout;
NS_ASSUME_NONNULL_BEGIN
#define ASPagerNodeDataSource ASPagerDataSource
@protocol ASPagerDataSource <NSObject>
@@ -52,6 +54,12 @@
*/
- (ASCellNodeBlock)pagerNode:(ASPagerNode *)pagerNode nodeBlockAtIndex:(NSInteger)index;
@end
@protocol ASPagerDelegate <ASCollectionDelegate>
@optional
/**
* Provides the constrained size range for measuring the node at the index path.
*
@@ -63,10 +71,6 @@
@end
@protocol ASPagerDelegate <ASCollectionDelegate>
@end
@interface ASPagerNode : ASCollectionNode
/**
@@ -82,14 +86,15 @@
/**
* Data Source is required, and uses a different protocol from ASCollectionNode.
*/
- (void)setDataSource:(id <ASPagerDataSource>)dataSource;
- (id <ASPagerDataSource>)dataSource;
- (void)setDataSource:(nullable id <ASPagerDataSource>)dataSource;
- (nullable id <ASPagerDataSource>)dataSource;
/**
* Delegate is optional, and uses the same protocol as ASCollectionNode.
* Delegate is optional.
* This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay...
*/
@property (nonatomic, weak) id <ASPagerDelegate> delegate;
- (void)setDelegate:(nullable id <ASPagerDelegate>)delegate;
- (nullable id <ASPagerDelegate>)delegate;
/**
* The underlying ASCollectionView object.
@@ -112,3 +117,5 @@
- (ASCellNode *)nodeForPageAtIndex:(NSInteger)index;
@end
NS_ASSUME_NONNULL_END

View File

@@ -15,18 +15,23 @@
#import "ASDisplayNode+Subclasses.h"
#import "ASPagerFlowLayout.h"
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor>
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionDelegate, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor>
{
ASPagerFlowLayout *_flowLayout;
ASPagerNodeProxy *_proxy;
__weak id <ASPagerNodeDataSource> _pagerDataSource;
__weak id <ASPagerDataSource> _pagerDataSource;
ASPagerNodeProxy *_proxyDataSource;
BOOL _pagerDataSourceImplementsNodeBlockAtIndex;
BOOL _pagerDataSourceImplementsConstrainedSizeForNode;
__weak id <ASPagerDelegate> _pagerDelegate;
ASPagerNodeProxy *_proxyDelegate;
BOOL _pagerDelegateImplementsConstrainedSizeForNode;
}
@end
@implementation ASPagerNode
@dynamic view, delegate, dataSource;
#pragma mark - Lifecycle
@@ -58,6 +63,7 @@
[super didLoad];
ASCollectionView *cv = self.view;
cv.asyncDelegate = self;
#if TARGET_OS_IOS
cv.pagingEnabled = YES;
cv.scrollsToTop = NO;
@@ -122,9 +128,10 @@
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{
if (_pagerDataSourceImplementsConstrainedSizeForNode) {
return [_pagerDataSource pagerNode:self constrainedSizeForNodeAtIndexPath:indexPath];
if (_pagerDelegateImplementsConstrainedSizeForNode) {
return [_pagerDelegate pagerNode:self constrainedSizeForNodeAtIndexPath:indexPath];
}
return ASSizeRangeMake(CGSizeZero, self.view.bounds.size);
}
@@ -135,26 +142,38 @@
return _pagerDataSource;
}
- (void)setDataSource:(id <ASPagerDataSource>)pagerDataSource
- (void)setDataSource:(id <ASPagerDataSource>)dataSource
{
if (pagerDataSource != _pagerDataSource) {
_pagerDataSource = pagerDataSource;
if (dataSource != _pagerDataSource) {
_pagerDataSource = dataSource;
_pagerDataSourceImplementsNodeBlockAtIndex = [_pagerDataSource respondsToSelector:@selector(pagerNode:nodeBlockAtIndex:)];
// Data source must implement pagerNode:nodeBlockAtIndex: or pagerNode:nodeAtIndex:
ASDisplayNodeAssertTrue(_pagerDataSourceImplementsNodeBlockAtIndex || [_pagerDataSource respondsToSelector:@selector(pagerNode:nodeAtIndex:)]);
_pagerDataSourceImplementsConstrainedSizeForNode = [_pagerDataSource respondsToSelector:@selector(pagerNode:constrainedSizeForNodeAtIndexPath:)];
_proxyDataSource = dataSource ? [[ASPagerNodeProxy alloc] initWithTarget:dataSource interceptor:self] : nil;
_proxy = pagerDataSource ? [[ASPagerNodeProxy alloc] initWithTarget:pagerDataSource interceptor:self] : nil;
super.dataSource = (id <ASCollectionDataSource>)_proxyDataSource;
}
}
super.dataSource = (id <ASCollectionDataSource>)_proxy;
- (void)setDelegate:(id<ASPagerDelegate>)delegate
{
if (delegate != _pagerDelegate) {
_pagerDelegate = delegate;
_pagerDelegateImplementsConstrainedSizeForNode = [_pagerDelegate respondsToSelector:@selector(pagerNode:constrainedSizeForNodeAtIndexPath:)];
_proxyDelegate = delegate ? [[ASPagerNodeProxy alloc] initWithTarget:delegate interceptor:self] : nil;
super.delegate = (id <ASCollectionDelegate>)_proxyDelegate;
}
}
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
{
[self setDataSource:nil];
[self setDelegate:nil];
}
@end

View File

@@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol ASCollectionViewLayoutInspecting <NSObject>
/**
* Asks the inspector to provide a constarained size range for the given collection view node.
* Asks the inspector to provide a constrained size range for the given collection view node.
*/
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;

View File

@@ -34,7 +34,7 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
@implementation ASCollectionViewLayoutInspector {
struct {
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
} _dataSourceFlags;
} _delegateFlags;
}
#pragma mark Lifecycle
@@ -43,26 +43,26 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
{
self = [super init];
if (self != nil) {
[self didChangeCollectionViewDataSource:collectionView.asyncDataSource];
[self didChangeCollectionViewDelegate:collectionView.asyncDelegate];
}
return self;
}
#pragma mark ASCollectionViewLayoutInspecting
- (void)didChangeCollectionViewDataSource:(id<ASCollectionDataSource>)dataSource
- (void)didChangeCollectionViewDelegate:(id<ASCollectionDelegate>)delegate
{
if (dataSource == nil) {
memset(&_dataSourceFlags, 0, sizeof(_dataSourceFlags));
if (delegate == nil) {
memset(&_delegateFlags, 0, sizeof(_delegateFlags));
} else {
_dataSourceFlags.implementsConstrainedSizeForNodeAtIndexPath = [dataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath = [delegate respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
}
}
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{
if (_dataSourceFlags.implementsConstrainedSizeForNodeAtIndexPath) {
return [collectionView.asyncDataSource collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath) {
return [collectionView.asyncDelegate collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
}
return NodeConstrainedSizeForScrollDirection(collectionView);
@@ -99,10 +99,10 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
struct {
unsigned int implementsReferenceSizeForHeader:1;
unsigned int implementsReferenceSizeForFooter:1;
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
} _delegateFlags;
struct {
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
unsigned int implementsNumberOfSectionsInCollectionView:1;
} _dataSourceFlags;
}
@@ -132,6 +132,7 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
} else {
_delegateFlags.implementsReferenceSizeForHeader = [delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)];
_delegateFlags.implementsReferenceSizeForFooter = [delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)];
_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath = [delegate respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
}
}
@@ -140,15 +141,14 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
if (dataSource == nil) {
memset(&_dataSourceFlags, 0, sizeof(_dataSourceFlags));
} else {
_dataSourceFlags.implementsConstrainedSizeForNodeAtIndexPath = [dataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
_dataSourceFlags.implementsNumberOfSectionsInCollectionView = [dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)];
}
}
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{
if (_dataSourceFlags.implementsConstrainedSizeForNodeAtIndexPath) {
return [collectionView.asyncDataSource collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath) {
return [collectionView.asyncDelegate collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
}
CGSize itemSize = _layout.itemSize;

View File

@@ -47,7 +47,7 @@ static UIColor *OverViewASPagerNodeRandomColor() {
#pragma mark - OverviewASPagerNode
@interface OverviewASPagerNode () <ASPagerNodeDataSource>
@interface OverviewASPagerNode () <ASPagerDataSource, ASPagerDelegate>
@property (nonatomic, strong) ASPagerNode *node;
@property (nonatomic, copy) NSArray *data;
@end
@@ -61,6 +61,7 @@ static UIColor *OverViewASPagerNodeRandomColor() {
_node = [ASPagerNode new];
_node.dataSource = self;
_node.delegate = self;
[self addSubnode:_node];
return self;

View File

@@ -19,7 +19,7 @@
#import "ViewController.h"
#import "GradientTableNode.h"
@interface ViewController () <ASPagerNodeDataSource>
@interface ViewController () <ASPagerDataSource, ASPagerDelegate>
{
ASPagerNode *_pagerNode;
}
@@ -38,6 +38,7 @@
_pagerNode = [[ASPagerNode alloc] init];
_pagerNode.dataSource = self;
_pagerNode.delegate = self;
[ASRangeController setShouldShowRangeDebugOverlay:YES];
// Could implement ASCollectionDelegate if we wanted extra callbacks, like from UIScrollView.