-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ASCollectionView] Add delegate bridging and index space translation for missing UICollectionViewLayout properties. #440
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -622,10 +622,16 @@ - (CGSize)sizeForElement:(ASCollectionElement *)element | |
return CGSizeZero; | ||
} | ||
|
||
// Get the indexPath from the pendingMap, as we're about to query the delegate (and it will reference its current data source). | ||
// Often this is a translation compared to the visibleMap where the element came from (UICollectionViewLayout requesting sizeForItem). | ||
NSIndexPath *indexPath = [_dataController.pendingMap indexPathForElement:element]; | ||
NSString *supplementaryKind = element.supplementaryElementKind; | ||
NSIndexPath *indexPath = [_dataController.visibleMap indexPathForElement:element]; | ||
ASSizeRange sizeRange; | ||
if (supplementaryKind == nil) { | ||
if (indexPath == nil) { | ||
// In this case, the latest data no longer has the element, so we can't ask the delegate for its latest constrained size. | ||
// The element is still visible, but will be deleted soon. We can reuse the last-known constrainedSize for the element. | ||
sizeRange = element.constrainedSize; | ||
} else if (supplementaryKind == nil) { | ||
sizeRange = [self dataController:_dataController constrainedSizeForNodeAtIndexPath:indexPath]; | ||
} else { | ||
sizeRange = [self dataController:_dataController constrainedSizeForSupplementaryNodeOfKind:supplementaryKind atIndexPath:indexPath]; | ||
|
@@ -949,7 +955,8 @@ - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSe | |
return [_dataController.visibleMap numberOfItemsInSection:section]; | ||
} | ||
|
||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath | ||
- (CGSize)collectionView:(UICollectionView *)collectionView | ||
layout:(UICollectionViewLayout *)layout sizeForItemAtIndexPath:(NSIndexPath *)indexPath | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since you changed the parameter name from |
||
{ | ||
ASDisplayNodeAssertMainThread(); | ||
ASCollectionElement *element = [_dataController.visibleMap elementForItemAtIndexPath:indexPath]; | ||
|
@@ -961,7 +968,9 @@ - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollection | |
ASCellNode *cell = element.node; | ||
if (cell.shouldUseUIKitCell) { | ||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) { | ||
CGSize size = [(id)_asyncDelegate collectionView:collectionView layout:collectionViewLayout sizeForItemAtIndexPath:indexPath]; | ||
CGSize size = [(id)_asyncDelegate collectionView:collectionView | ||
layout:layout | ||
sizeForItemAtIndexPath:indexPath]; | ||
cell.style.preferredSize = size; | ||
return size; | ||
} | ||
|
@@ -970,45 +979,118 @@ - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollection | |
return [self sizeForElement:element]; | ||
} | ||
|
||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)layout referenceSizeForHeaderInSection:(NSInteger)section | ||
- (NSIndexPath *)pendingIndexPathForSection:(NSInteger)section | ||
{ | ||
// NOTE: For now, we don't translate length = 1 NSIndexPaths between spaces. Use the 0th item until then. | ||
NSIndexPath *sectionIndexPath = [NSIndexPath indexPathForItem:0 inSection:section]; | ||
ASCollectionElement *element = [_dataController.visibleMap elementForItemAtIndexPath:sectionIndexPath]; | ||
NSIndexPath *pendingIndexPath = element ? [_dataController.pendingMap indexPathForElement:element] : nil; | ||
return pendingIndexPath; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be Currently |
||
|
||
} | ||
|
||
#define ASFlowLayoutDefault(layout, property, default) \ | ||
({ \ | ||
UICollectionViewFlowLayout *flowLayout = ASDynamicCast(layout, UICollectionViewFlowLayout); \ | ||
flowLayout ? flowLayout.property : default; \ | ||
}) | ||
|
||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView | ||
layout:(UICollectionViewLayout *)layout insetForSectionAtIndex:(NSInteger)section | ||
{ | ||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) { | ||
NSIndexPath *appIndexPath = [self pendingIndexPathForSection:section]; | ||
// If the section no longer exists in the latest dataSource state, fall through to the defaults below. | ||
if (appIndexPath) { | ||
return [(id)_asyncDelegate collectionView:collectionView | ||
layout:layout insetForSectionAtIndex:appIndexPath.section]; | ||
} | ||
} | ||
return ASFlowLayoutDefault(layout, sectionInset, UIEdgeInsetsZero); | ||
} | ||
|
||
- (CGFloat)collectionView:(UICollectionView *)collectionView | ||
layout:(UICollectionViewLayout *)layout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section | ||
{ | ||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) { | ||
NSIndexPath *appIndexPath = [self pendingIndexPathForSection:section]; | ||
// If the section no longer exists in the latest dataSource state, fall through to the defaults below. | ||
if (appIndexPath) { | ||
return [(id)_asyncDelegate collectionView:collectionView | ||
layout:layout minimumInteritemSpacingForSectionAtIndex:appIndexPath.section]; | ||
} | ||
} | ||
return ASFlowLayoutDefault(layout, minimumInteritemSpacing, 10.0); // UIKit documents this default to be 10.0. | ||
} | ||
|
||
- (CGFloat)collectionView:(UICollectionView *)collectionView | ||
layout:(UICollectionViewLayout *)layout minimumLineSpacingForSectionAtIndex:(NSInteger)section | ||
{ | ||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) { | ||
NSIndexPath *appIndexPath = [self pendingIndexPathForSection:section]; | ||
// If the section no longer exists in the latest dataSource state, fall through to the defaults below. | ||
if (appIndexPath) { | ||
return [(id)_asyncDelegate collectionView:collectionView | ||
layout:layout minimumLineSpacingForSectionAtIndex:appIndexPath.section]; | ||
} | ||
} | ||
return ASFlowLayoutDefault(layout, minimumLineSpacing, 10.0); // UIKit documents this default to be 10.0. | ||
} | ||
|
||
- (CGSize)collectionView:(UICollectionView *)collectionView | ||
layout:(UICollectionViewLayout *)layout referenceSizeForHeaderInSection:(NSInteger)section | ||
{ | ||
ASDisplayNodeAssertMainThread(); | ||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:section]; | ||
ASCollectionElement *element = [_dataController.visibleMap supplementaryElementOfKind:UICollectionElementKindSectionHeader | ||
atIndexPath:indexPath]; | ||
if (element == nil) { | ||
return CGSizeZero; | ||
return ASFlowLayoutDefault(layout, headerReferenceSize, CGSizeZero); // UIKit documents this default to be CGSizeZero. | ||
} | ||
|
||
if (element.node.shouldUseUIKitCell && _asyncDelegateFlags.interop) { | ||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)]) { | ||
return [(id)_asyncDelegate collectionView:collectionView layout:layout referenceSizeForHeaderInSection:section]; | ||
NSIndexPath *appIndexPath = [self pendingIndexPathForSection:section]; | ||
// If the section no longer exists in the latest dataSource state, fall through to the defaults below. | ||
if (appIndexPath) { | ||
return [(id)_asyncDelegate collectionView:collectionView layout:layout referenceSizeForHeaderInSection:appIndexPath.section]; | ||
} | ||
} | ||
return ASFlowLayoutDefault(layout, headerReferenceSize, CGSizeZero); // UIKit documents this default to be CGSizeZero. | ||
} else { | ||
// In this case, we have an ASCellNode-based Supplementary Node as a header. Ask it what size it wants to be. | ||
return [self sizeForElement:element]; | ||
} | ||
|
||
return [self sizeForElement:element]; | ||
} | ||
|
||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)layout referenceSizeForFooterInSection:(NSInteger)section | ||
- (CGSize)collectionView:(UICollectionView *)collectionView | ||
layout:(UICollectionViewLayout *)layout referenceSizeForFooterInSection:(NSInteger)section | ||
{ | ||
ASDisplayNodeAssertMainThread(); | ||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:section]; | ||
ASCollectionElement *element = [_dataController.visibleMap supplementaryElementOfKind:UICollectionElementKindSectionFooter | ||
atIndexPath:indexPath]; | ||
if (element == nil) { | ||
return CGSizeZero; | ||
return ASFlowLayoutDefault(layout, footerReferenceSize, CGSizeZero); // UIKit documents this default to be CGSizeZero. | ||
} | ||
|
||
if (element.node.shouldUseUIKitCell && _asyncDelegateFlags.interop) { | ||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) { | ||
return [(id)_asyncDelegate collectionView:collectionView layout:layout referenceSizeForFooterInSection:section]; | ||
NSIndexPath *appIndexPath = [self pendingIndexPathForSection:section]; | ||
// If the section no longer exists in the latest dataSource state, fall through to the defaults below. | ||
if (appIndexPath) { | ||
return [(id)_asyncDelegate collectionView:collectionView layout:layout referenceSizeForFooterInSection:appIndexPath.section]; | ||
} | ||
} | ||
return ASFlowLayoutDefault(layout, footerReferenceSize, CGSizeZero); // UIKit documents this default to be CGSizeZero. | ||
} else { | ||
// In this case, we have an ASCellNode-based Supplementary Node as a footer. Ask it what size it wants to be. | ||
return [self sizeForElement:element]; | ||
} | ||
|
||
return [self sizeForElement:element]; | ||
} | ||
|
||
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath | ||
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView | ||
viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath | ||
{ | ||
if ([_registeredSupplementaryKinds containsObject:kind] == NO) { | ||
[self registerSupplementaryNodeOfKind:kind]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"visible" is quite misleading here, and so does the "vibisbleMap" name. We should change it to "current" or something similar that indicates that the element is still recognized by UIKit objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I agree that if we clarified the terminology here, and used it consistently everywhere (and we could even start putting it in method names, or comments at the start of methods), it would be easier to ensure correctness.
Ideas for "UIKit" space:
Ideas for "Latest" space:
I feel like there must be a better, more parallel set of names. One trouble with "current" is that you could imagine that being the current UIKit state, or the current App state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UIDataSourceTranslating
uses "Presentation." I kind of like that name.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"DataSource" and "Presentation", or "Processed" and "Presenting"?