-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[example/CustomCollectionView] Implement MosaicCollectionLayoutDelega…
…te (#28) * Implement MosaicCollectionLayoutDelegate * Update licenses * Address comments * Fix license
- Loading branch information
1 parent
d4725a5
commit 7dd8361
Showing
8 changed files
with
230 additions
and
293 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
examples/CustomCollectionView/Sample.xcworkspace/contents.xcworkspacedata
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
examples/CustomCollectionView/Sample/MosaicCollectionLayoutDelegate.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// | ||
// MosaicCollectionLayoutDelegate.h | ||
// Texture | ||
// | ||
// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
|
||
#import <UIKit/UIKit.h> | ||
#import <AsyncDisplayKit/AsyncDisplayKit.h> | ||
|
||
@interface MosaicCollectionLayoutDelegate : NSObject <ASCollectionLayoutDelegate> | ||
|
||
- (instancetype)initWithNumberOfColumns:(NSInteger)numberOfColumns headerHeight:(CGFloat)headerHeight; | ||
|
||
@end |
165 changes: 165 additions & 0 deletions
165
examples/CustomCollectionView/Sample/MosaicCollectionLayoutDelegate.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// | ||
// MosaicCollectionLayoutDelegate.m | ||
// Texture | ||
// | ||
// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
|
||
#import "MosaicCollectionLayoutDelegate.h" | ||
#import "ImageCellNode.h" | ||
|
||
#import <AsyncDisplayKit/ASCollectionElement.h> | ||
|
||
@implementation MosaicCollectionLayoutDelegate { | ||
// Read-only properties | ||
NSInteger _numberOfColumns; | ||
CGFloat _headerHeight; | ||
CGFloat _columnSpacing; | ||
UIEdgeInsets _sectionInset; | ||
UIEdgeInsets _interItemSpacing; | ||
} | ||
|
||
- (instancetype)initWithNumberOfColumns:(NSInteger)numberOfColumns headerHeight:(CGFloat)headerHeight | ||
{ | ||
self = [super init]; | ||
if (self != nil) { | ||
_numberOfColumns = numberOfColumns; | ||
_headerHeight = headerHeight; | ||
_columnSpacing = 10.0; | ||
_sectionInset = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0); | ||
_interItemSpacing = UIEdgeInsetsMake(10.0, 0, 10.0, 0); | ||
} | ||
return self; | ||
} | ||
|
||
- (id)additionalInfoForLayoutWithElements:(ASElementMap *)elements | ||
{ | ||
return nil; | ||
} | ||
|
||
- (ASCollectionLayoutState *)calculateLayoutWithContext:(ASCollectionLayoutContext *)context | ||
{ | ||
CGFloat layoutWidth = context.viewportSize.width; | ||
ASElementMap *elements = context.elements; | ||
CGFloat top = 0; | ||
|
||
// TODO use +[NSMapTable elementToLayoutAttributesTable] | ||
NSMapTable<ASCollectionElement *, UICollectionViewLayoutAttributes *> *attrsMap = [NSMapTable mapTableWithKeyOptions:(NSMapTableObjectPointerPersonality | NSMapTableWeakMemory) valueOptions:NSMapTableStrongMemory]; | ||
NSMutableArray *columnHeights = [NSMutableArray array]; | ||
|
||
NSInteger numberOfSections = [elements numberOfSections]; | ||
for (NSUInteger section = 0; section < numberOfSections; section++) { | ||
NSInteger numberOfItems = [elements numberOfItemsInSection:section]; | ||
|
||
top += _sectionInset.top; | ||
|
||
if (_headerHeight > 0) { | ||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:section]; | ||
ASCollectionElement *element = [elements supplementaryElementOfKind:UICollectionElementKindSectionHeader | ||
atIndexPath:indexPath]; | ||
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader | ||
withIndexPath:indexPath]; | ||
|
||
ASSizeRange sizeRange = [self sizeRangeForHeaderOfSection:section withLayoutWidth:layoutWidth]; | ||
CGSize size = [element.node layoutThatFits:sizeRange].size; | ||
CGRect frame = CGRectMake(_sectionInset.left, top, size.width, size.height); | ||
|
||
attrs.frame = frame; | ||
[attrsMap setObject:attrs forKey:element]; | ||
top = CGRectGetMaxY(frame); | ||
} | ||
|
||
[columnHeights addObject:[NSMutableArray array]]; | ||
for (NSUInteger idx = 0; idx < _numberOfColumns; idx++) { | ||
[columnHeights[section] addObject:@(top)]; | ||
} | ||
|
||
CGFloat columnWidth = [self _columnWidthForSection:section withLayoutWidth:layoutWidth]; | ||
for (NSUInteger idx = 0; idx < numberOfItems; idx++) { | ||
NSUInteger columnIndex = [self _shortestColumnIndexInSection:section withColumnHeights:columnHeights]; | ||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:idx inSection:section]; | ||
ASCollectionElement *element = [elements elementForItemAtIndexPath:indexPath]; | ||
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; | ||
|
||
ASSizeRange sizeRange = [self sizeRangeForItem:element.node atIndexPath:indexPath withLayoutWidth:layoutWidth]; | ||
CGSize size = [element.node layoutThatFits:sizeRange].size; | ||
CGPoint position = CGPointMake(_sectionInset.left + (columnWidth + _columnSpacing) * columnIndex, | ||
[columnHeights[section][columnIndex] floatValue]); | ||
CGRect frame = CGRectMake(position.x, position.y, size.width, size.height); | ||
|
||
attrs.frame = frame; | ||
[attrsMap setObject:attrs forKey:element]; | ||
// TODO Profile and avoid boxing if there are significant retain/release overheads | ||
columnHeights[section][columnIndex] = @(CGRectGetMaxY(frame) + _interItemSpacing.bottom); | ||
} | ||
|
||
NSUInteger columnIndex = [self _tallestColumnIndexInSection:section withColumnHeights:columnHeights]; | ||
top = [columnHeights[section][columnIndex] floatValue] - _interItemSpacing.bottom + _sectionInset.bottom; | ||
|
||
for (NSUInteger idx = 0; idx < [columnHeights[section] count]; idx++) { | ||
columnHeights[section][idx] = @(top); | ||
} | ||
} | ||
|
||
CGFloat contentHeight = [[[columnHeights lastObject] firstObject] floatValue]; | ||
CGSize contentSize = CGSizeMake(layoutWidth, contentHeight); | ||
return [[ASCollectionLayoutState alloc] initWithElements:elements contentSize:contentSize elementToLayoutArrtibutesMap:attrsMap]; | ||
} | ||
|
||
- (CGFloat)_widthForSection:(NSUInteger)section withLayoutWidth:(CGFloat)layoutWidth | ||
{ | ||
return layoutWidth - _sectionInset.left - _sectionInset.right; | ||
} | ||
|
||
- (CGFloat)_columnWidthForSection:(NSUInteger)section withLayoutWidth:(CGFloat)layoutWidth | ||
{ | ||
return ([self _widthForSection:section withLayoutWidth:layoutWidth] - ((_numberOfColumns - 1) * _columnSpacing)) / _numberOfColumns; | ||
} | ||
|
||
- (ASSizeRange)sizeRangeForItem:(ASCellNode *)item atIndexPath:(NSIndexPath *)indexPath withLayoutWidth:(CGFloat)layoutWidth; | ||
{ | ||
CGFloat itemWidth = [self _columnWidthForSection:indexPath.section withLayoutWidth:layoutWidth]; | ||
if ([item isKindOfClass:[ImageCellNode class]]) { | ||
return ASSizeRangeMake(CGSizeMake(itemWidth, 0), CGSizeMake(itemWidth, CGFLOAT_MAX)); | ||
} else { | ||
return ASSizeRangeMake(CGSizeMake(itemWidth, itemWidth)); // In kShowUICollectionViewCells = YES mode, make those cells itemWidth x itemWidth. | ||
} | ||
} | ||
|
||
- (ASSizeRange)sizeRangeForHeaderOfSection:(NSInteger)section withLayoutWidth:(CGFloat)layoutWidth | ||
{ | ||
return ASSizeRangeMake(CGSizeMake(0, _headerHeight), CGSizeMake([self _widthForSection:section withLayoutWidth:layoutWidth], _headerHeight)); | ||
} | ||
|
||
- (NSUInteger)_tallestColumnIndexInSection:(NSUInteger)section withColumnHeights:(NSArray *)columnHeights | ||
{ | ||
__block NSUInteger index = 0; | ||
__block CGFloat tallestHeight = 0; | ||
[columnHeights[section] enumerateObjectsUsingBlock:^(NSNumber *height, NSUInteger idx, BOOL *stop) { | ||
if (height.floatValue > tallestHeight) { | ||
index = idx; | ||
tallestHeight = height.floatValue; | ||
} | ||
}]; | ||
return index; | ||
} | ||
|
||
- (NSUInteger)_shortestColumnIndexInSection:(NSUInteger)section withColumnHeights:(NSArray *)columnHeights | ||
{ | ||
__block NSUInteger index = 0; | ||
__block CGFloat shortestHeight = CGFLOAT_MAX; | ||
[columnHeights[section] enumerateObjectsUsingBlock:^(NSNumber *height, NSUInteger idx, BOOL *stop) { | ||
if (height.floatValue < shortestHeight) { | ||
index = idx; | ||
shortestHeight = height.floatValue; | ||
} | ||
}]; | ||
return index; | ||
} | ||
|
||
@end |
40 changes: 0 additions & 40 deletions
40
examples/CustomCollectionView/Sample/MosaicCollectionViewLayout.h
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.