Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

Don't Cache ConstrainedSize in ASCollectionView #3136

Merged
merged 3 commits into from
Mar 6, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions Source/ASCollectionView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#import <AsyncDisplayKit/ASCollectionView+Undeprecated.h>
#import <AsyncDisplayKit/_ASHierarchyChangeSet.h>
#import <AsyncDisplayKit/CoreGraphics+ASConvenience.h>
#import <AsyncDisplayKit/ASLayout.h>

/**
* A macro to get self.collectionNode and assign it to a local variable, or return
Expand Down Expand Up @@ -606,9 +607,28 @@ - (BOOL)zeroContentInsets
return _zeroContentInsets;
}

/// Uses latest size range from data source and -layoutThatFits:.
- (CGSize)sizeForElement:(ASCollectionElement *)element
{
ASDisplayNodeAssertMainThread();

NSString *supplementaryKind = element.supplementaryElementKind;
NSIndexPath *indexPath = [_dataController.visibleMap indexPathForElement:element];
ASSizeRange sizeRange;
if (supplementaryKind == nil) {
sizeRange = [self dataController:_dataController constrainedSizeForNodeAtIndexPath:indexPath];
} else {
sizeRange = [self dataController:_dataController constrainedSizeForSupplementaryNodeOfKind:supplementaryKind atIndexPath:indexPath];
}
return [element.node layoutThatFits:sizeRange].size;
}

- (CGSize)calculatedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{
return [[self nodeForItemAtIndexPath:indexPath] calculatedSize];
ASDisplayNodeAssertMainThread();

ASCollectionElement *e = [_dataController.visibleMap elementForItemAtIndexPath:indexPath];
return [self sizeForElement:e];
}

- (ASCellNode *)nodeForItemAtIndexPath:(NSIndexPath *)indexPath
Expand Down Expand Up @@ -893,37 +913,45 @@ - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSe

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
ASDisplayNodeAssertMainThread();
ASCellNode *cell = [self nodeForItemAtIndexPath:indexPath];
if (cell.shouldUseUIKitCell) {
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
return [(id)_asyncDelegate collectionView:collectionView layout:collectionViewLayout sizeForItemAtIndexPath:indexPath];
}
}
return cell.calculatedSize;
ASCollectionElement *e = [_dataController.visibleMap elementForItemAtIndexPath:indexPath];
return [self sizeForElement:e];
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)layout referenceSizeForHeaderInSection:(NSInteger)section
{
ASDisplayNodeAssertMainThread();
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:section];
ASCellNode *cell = [self supplementaryNodeForElementKind:UICollectionElementKindSectionHeader
atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
atIndexPath:indexPath];
if (cell.shouldUseUIKitCell && _asyncDelegateFlags.interop) {
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)]) {
return [(id)_asyncDelegate collectionView:collectionView layout:layout referenceSizeForHeaderInSection:section];
}
}
return cell.calculatedSize;
ASCollectionElement *e = [_dataController.visibleMap supplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
return [self sizeForElement:e];
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)layout referenceSizeForFooterInSection:(NSInteger)section
{
ASDisplayNodeAssertMainThread();
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:section];
ASCellNode *cell = [self supplementaryNodeForElementKind:UICollectionElementKindSectionFooter
atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
atIndexPath:indexPath];
if (cell.shouldUseUIKitCell && _asyncDelegateFlags.interop) {
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
return [(id)_asyncDelegate collectionView:collectionView layout:layout referenceSizeForFooterInSection:section];
}
}
return cell.calculatedSize;
ASCollectionElement *e = [_dataController.visibleMap supplementaryElementOfKind:UICollectionElementKindSectionFooter atIndexPath:indexPath];
return [self sizeForElement:e];
}

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
Expand Down Expand Up @@ -1918,6 +1946,15 @@ - (void)didMoveToWindow
#pragma mark ASCALayerExtendedDelegate

/**
* TODO: This code was added when we used @c calculatedSize as the size for
* items (e.g. collectionView:layout:sizeForItemAtIndexPath:) and so it
* was critical that we remeasured all nodes at this time.
*
* The assumption was that cv-bounds-size-change -> constrained-size-change, so
* this was the time when we get new constrained sizes for all items and remeasure
* them. However, the constrained sizes for items can be invalidated for many other
* reasons, hence why we never reuse the old constrained size anymore.
*
* UICollectionView inadvertently triggers a -prepareLayout call to its layout object
* between [super setFrame:] and [self layoutSubviews] during size changes. So we need
* to get in there and re-measure our nodes before that -prepareLayout call.
Expand Down