Skip to content
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

[example/CustomCollectionView] Implement MosaicCollectionLayoutDelegate #28

Merged
merged 4 commits into from May 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions examples/CustomCollectionView/Sample.xcodeproj/project.pbxproj
Expand Up @@ -7,7 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
25A1FA851C02F7AC00193875 /* MosaicCollectionViewLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 25A1FA841C02F7AC00193875 /* MosaicCollectionViewLayout.m */; };
25A1FA851C02F7AC00193875 /* MosaicCollectionLayoutDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 25A1FA841C02F7AC00193875 /* MosaicCollectionLayoutDelegate.m */; };
25A1FA881C02FCB000193875 /* ImageCellNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25A1FA871C02FCB000193875 /* ImageCellNode.m */; };
576F970133B34DFD583D5CE4 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC0FB9EE0030992E8FBC0A0 /* libPods-Sample.a */; };
80364CCA1E3D95A90094400C /* ImageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 80364CC91E3D95A90094400C /* ImageCollectionViewCell.m */; };
Expand All @@ -19,8 +19,7 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
25A1FA831C02F7AC00193875 /* MosaicCollectionViewLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MosaicCollectionViewLayout.h; sourceTree = "<group>"; };
25A1FA841C02F7AC00193875 /* MosaicCollectionViewLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MosaicCollectionViewLayout.m; sourceTree = "<group>"; };
25A1FA841C02F7AC00193875 /* MosaicCollectionLayoutDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MosaicCollectionLayoutDelegate.m; sourceTree = "<group>"; };
25A1FA861C02FCB000193875 /* ImageCellNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageCellNode.h; sourceTree = "<group>"; };
25A1FA871C02FCB000193875 /* ImageCellNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageCellNode.m; sourceTree = "<group>"; };
4CC0FB9EE0030992E8FBC0A0 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
Expand All @@ -36,6 +35,7 @@
AC3C4A691A11F47200143C57 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
E2F287D91FFDEA2A747630CE /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
E5D73A3A1EA6766B006418A8 /* MosaicCollectionLayoutDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MosaicCollectionLayoutDelegate.h; sourceTree = "<group>"; };
F36BCD8EBAF79797AB5C6708 /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -81,8 +81,8 @@
AC3C4A601A11F47200143C57 /* Sample */ = {
isa = PBXGroup;
children = (
25A1FA831C02F7AC00193875 /* MosaicCollectionViewLayout.h */,
25A1FA841C02F7AC00193875 /* MosaicCollectionViewLayout.m */,
E5D73A3A1EA6766B006418A8 /* MosaicCollectionLayoutDelegate.h */,
25A1FA841C02F7AC00193875 /* MosaicCollectionLayoutDelegate.m */,
AC3C4A651A11F47200143C57 /* AppDelegate.h */,
AC3C4A661A11F47200143C57 /* AppDelegate.m */,
AC3C4A681A11F47200143C57 /* ViewController.h */,
Expand Down Expand Up @@ -238,7 +238,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
25A1FA851C02F7AC00193875 /* MosaicCollectionViewLayout.m in Sources */,
25A1FA851C02F7AC00193875 /* MosaicCollectionLayoutDelegate.m in Sources */,
AC3C4A6A1A11F47200143C57 /* ViewController.m in Sources */,
AC3C4A671A11F47200143C57 /* AppDelegate.m in Sources */,
AC3C4A641A11F47200143C57 /* main.m in Sources */,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 13 additions & 12 deletions examples/CustomCollectionView/Sample/ImageCellNode.m
@@ -1,20 +1,18 @@
//
// ImageCellNode.m
// Sample
//
// Created by McCallum, Levi on 11/22/15.
// Texture
//
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
// grant of patent rights can be found in the PATENTS file in the same directory.
//
// Modifications to this file made after 4/13/2017 are: Copyright (c) 2017-present,
// Pinterest, Inc. 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
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// http://www.apache.org/licenses/LICENSE-2.0
//

#import "ImageCellNode.h"
Expand All @@ -36,7 +34,10 @@ - (id)initWithImage:(UIImage *)image

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:_imageNode];
CGSize imageSize = self.image.size;
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero
child:[ASRatioLayoutSpec ratioLayoutSpecWithRatio:imageSize.height/imageSize.width
child:_imageNode]];
}

- (void)setImage:(UIImage *)image
Expand Down
@@ -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 examples/CustomCollectionView/Sample/MosaicCollectionLayoutDelegate.m
@@ -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 examples/CustomCollectionView/Sample/MosaicCollectionViewLayout.h

This file was deleted.