Skip to content

Commit

Permalink
[ASCollectionView] Improve code sharing of UIKit size method calls; e…
Browse files Browse the repository at this point in the history
…nsure delegate invalidation re-fetches supplementary sizes too.
  • Loading branch information
appleguy committed Oct 8, 2017
1 parent dc188c6 commit e2a9ffb
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 49 deletions.
107 changes: 59 additions & 48 deletions Source/ASCollectionView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#import <AsyncDisplayKit/ASDataController.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
#import <AsyncDisplayKit/ASDisplayNode+FrameworkPrivate.h>
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
#import <AsyncDisplayKit/ASElementMap.h>
#import <AsyncDisplayKit/ASInternalHelpers.h>
#import <AsyncDisplayKit/UICollectionViewLayout+ASConvenience.h>
Expand Down Expand Up @@ -63,6 +64,14 @@
return __val; \
}

#define ASIndexPathForSection(section) [NSIndexPath indexPathForItem:0 inSection:section]

#define ASFlowLayoutDefault(layout, property, default) \
({ \
UICollectionViewFlowLayout *flowLayout = ASDynamicCast(layout, UICollectionViewFlowLayout); \
flowLayout ? flowLayout.property : default; \
})

/// What, if any, invalidation should we perform during the next -layoutSubviews.
typedef NS_ENUM(NSUInteger, ASCollectionViewInvalidationStyle) {
/// Perform no invalidation.
Expand Down Expand Up @@ -776,23 +785,20 @@ - (void)setUsesSynchronousDataLoading:(BOOL)usesSynchronousDataLoading
}

- (void)invalidateFlowLayoutDelegateMetrics {
UICollectionViewLayout *layout = self.collectionViewLayout;
CGSize defaultSize = ({
UICollectionViewFlowLayout *flowLayout = ASDynamicCast(layout, UICollectionViewFlowLayout);
flowLayout ? flowLayout.itemSize : CGSizeZero;
});

for (ASCollectionElement *element in self.dataController.pendingMap.itemElements) {
for (ASCollectionElement *element in self.dataController.pendingMap) {
// This may be either a Supplementary or Item type element.
// For UIKit passthrough cells of either type, re-fetch their sizes from the standard UIKit delegate methods.
ASCellNode *node = element.node;
if (node.shouldUseUIKitCell) {
NSIndexPath *indexPath = [self indexPathForNode:node];
CGSize size = CGSizeZero;
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
size = [(id)_asyncDelegate collectionView:self layout:layout sizeForItemAtIndexPath:indexPath];
} else {
size = defaultSize;
NSString *kind = [element supplementaryElementKind];
CGSize previousSize = node.style.preferredSize;
CGSize size = [self sizeForUIKitCellWithKind:kind atIndexPath:indexPath];

if (!CGSizeEqualToSize(previousSize, size)) {
node.style.preferredSize = size;
[node invalidateCalculatedLayout];
}
node.style.preferredSize = size;
}
}
}
Expand Down Expand Up @@ -987,13 +993,6 @@ - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSe
return [_dataController.visibleMap numberOfItemsInSection:section];
}

#define ASIndexPathForSection(section) [NSIndexPath indexPathForItem:0 inSection:section]
#define ASFlowLayoutDefault(layout, property, default) \
({ \
UICollectionViewFlowLayout *flowLayout = ASDynamicCast(layout, UICollectionViewFlowLayout); \
flowLayout ? flowLayout.property : default; \
})

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)layout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
Expand Down Expand Up @@ -1759,15 +1758,7 @@ - (ASCellNodeBlock)dataController:(ASDataController *)dataController nodeBlockAt

if (block == nil) {
if (_asyncDataSourceFlags.interop) {
UICollectionViewLayout *layout = self.collectionViewLayout;
CGSize preferredSize = CGSizeZero;
SEL sizeForItem = @selector(collectionView:layout:sizeForItemAtIndexPath:);
if ([_asyncDelegate respondsToSelector:sizeForItem]) {
preferredSize = [(id)_asyncDelegate collectionView:self layout:layout
sizeForItemAtIndexPath:indexPath];
} else {
preferredSize = ASFlowLayoutDefault(layout, itemSize, CGSizeZero);
}
CGSize preferredSize = [self sizeForUIKitCellWithKind:nil atIndexPath:indexPath];
block = ^{
ASCellNode *cell = [[ASCellNode alloc] init];
cell.shouldUseUIKitCell = YES;
Expand Down Expand Up @@ -1843,6 +1834,7 @@ - (BOOL)dataController:(ASDataController *)dataController presentedSizeForElemen

- (ASCellNodeBlock)dataController:(ASDataController *)dataController supplementaryNodeBlockOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
ASDisplayNodeAssertMainThread();
ASCellNodeBlock nodeBlock = nil;
ASCellNode *node = nil;
if (_asyncDataSourceFlags.collectionNodeNodeBlockForSupplementaryElement) {
Expand All @@ -1862,27 +1854,12 @@ - (ASCellNodeBlock)dataController:(ASDataController *)dataController supplementa
if (node) {
nodeBlock = ^{ return node; };
} else {
BOOL useUIKitCell = _asyncDataSourceFlags.interop;
// In this case, the app code returned nil for the node and the nodeBlock.
// If the UIKit method is implemented, then we should use it. Otherwise the CGSizeZero default will cause UIKit to not show it.
CGSize preferredSize = CGSizeZero;
BOOL useUIKitCell = _asyncDataSourceFlags.interopViewForSupplementaryElement;
if (useUIKitCell) {
UICollectionViewLayout *layout = self.collectionViewLayout;
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
SEL sizeForHeader = @selector(collectionView:layout:referenceSizeForHeaderInSection:);
if ([_asyncDelegate respondsToSelector:sizeForHeader]) {
preferredSize = [(id)_asyncDelegate collectionView:self layout:layout
referenceSizeForHeaderInSection:indexPath.section];
} else {
preferredSize = ASFlowLayoutDefault(layout, headerReferenceSize, CGSizeZero);
}
} else if ([kind isEqualToString:UICollectionElementKindSectionFooter]) {
SEL sizeForFooter = @selector(collectionView:layout:referenceSizeForFooterInSection:);
if ([_asyncDelegate respondsToSelector:sizeForFooter]) {
preferredSize = [(id)_asyncDelegate collectionView:self layout:layout
referenceSizeForFooterInSection:indexPath.section];
} else {
preferredSize = ASFlowLayoutDefault(layout, footerReferenceSize, CGSizeZero);
}
}
preferredSize = [self sizeForUIKitCellWithKind:kind atIndexPath:indexPath];
}
nodeBlock = ^{
ASCellNode *node = [[ASCellNode alloc] init];
Expand All @@ -1896,6 +1873,40 @@ - (ASCellNodeBlock)dataController:(ASDataController *)dataController supplementa
return nodeBlock;
}

- (CGSize)sizeForUIKitCellWithKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
CGSize size = CGSizeZero;
UICollectionViewLayout *l = self.collectionViewLayout;

if (kind == nil) {
ASDisplayNodeAssert(_asyncDataSourceFlags.interop, @"This code should not be called except for UIKit passthrough compatibility");
SEL sizeForItem = @selector(collectionView:layout:sizeForItemAtIndexPath:);
if ([_asyncDelegate respondsToSelector:sizeForItem]) {
size = [(id)_asyncDelegate collectionView:self layout:l sizeForItemAtIndexPath:indexPath];
} else {
size = ASFlowLayoutDefault(l, itemSize, CGSizeZero);
}
} else if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
ASDisplayNodeAssert(_asyncDataSourceFlags.interopViewForSupplementaryElement, @"This code should not be called except for UIKit passthrough compatibility");
SEL sizeForHeader = @selector(collectionView:layout:referenceSizeForHeaderInSection:);
if ([_asyncDelegate respondsToSelector:sizeForHeader]) {
size = [(id)_asyncDelegate collectionView:self layout:l referenceSizeForHeaderInSection:indexPath.section];
} else {
size = ASFlowLayoutDefault(l, headerReferenceSize, CGSizeZero);
}
} else if ([kind isEqualToString:UICollectionElementKindSectionFooter]) {
ASDisplayNodeAssert(_asyncDataSourceFlags.interopViewForSupplementaryElement, @"This code should not be called except for UIKit passthrough compatibility");
SEL sizeForFooter = @selector(collectionView:layout:referenceSizeForFooterInSection:);
if ([_asyncDelegate respondsToSelector:sizeForFooter]) {
size = [(id)_asyncDelegate collectionView:self layout:l referenceSizeForFooterInSection:indexPath.section];
} else {
size = ASFlowLayoutDefault(l, footerReferenceSize, CGSizeZero);
}
}

return size;
}

- (NSArray<NSString *> *)dataController:(ASDataController *)dataController supplementaryNodeKindsInSections:(NSIndexSet *)sections
{
if (_asyncDataSourceFlags.collectionNodeSupplementaryElementKindsInSection) {
Expand Down
2 changes: 1 addition & 1 deletion Source/Details/ASDataController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ - (void)_relayoutAllNodes
element.constrainedSize = newConstrainedSize;

// Node may not be allocated yet (e.g node virtualization or same size optimization)
// Call context.nodeIfAllocated here to avoid immature node allocation and layout
// Call context.nodeIfAllocated here to avoid premature node allocation and layout
ASCellNode *node = element.nodeIfAllocated;
if (node) {
[self _layoutNode:node withConstrainedSize:newConstrainedSize];
Expand Down

0 comments on commit e2a9ffb

Please sign in to comment.