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

[ASCollectionLayout] Add ASCollectionGalleryLayoutSizeProviding #451

Merged
merged 3 commits into from
Jul 18, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AsyncDisplayKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
DEFAD8131CC48914000527C4 /* ASVideoNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEC47E01C20C2DD00EC1693 /* ASVideoNode.mm */; };
E51B78BF1F028ABF00E32604 /* ASLayoutFlatteningTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E51B78BD1F01A0EE00E32604 /* ASLayoutFlatteningTests.m */; };
E54E00721F1D3828000B30D7 /* ASPagerNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = E54E00711F1D3828000B30D7 /* ASPagerNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; };
E54E81FC1EB357BD00FFE8E1 /* ASPageTable.h in Headers */ = {isa = PBXBuildFile; fileRef = E54E81FA1EB357BD00FFE8E1 /* ASPageTable.h */; };
E54E81FD1EB357BD00FFE8E1 /* ASPageTable.m in Sources */ = {isa = PBXBuildFile; fileRef = E54E81FB1EB357BD00FFE8E1 /* ASPageTable.m */; };
E55D86331CA8A14000A0C26F /* ASLayoutElement.mm in Sources */ = {isa = PBXBuildFile; fileRef = E55D86311CA8A14000A0C26F /* ASLayoutElement.mm */; };
Expand Down Expand Up @@ -912,6 +913,7 @@
E51B78BD1F01A0EE00E32604 /* ASLayoutFlatteningTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASLayoutFlatteningTests.m; sourceTree = "<group>"; };
E52405B21C8FEF03004DC8E7 /* ASLayoutTransition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASLayoutTransition.mm; sourceTree = "<group>"; };
E52405B41C8FEF16004DC8E7 /* ASLayoutTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutTransition.h; sourceTree = "<group>"; };
E54E00711F1D3828000B30D7 /* ASPagerNode+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASPagerNode+Beta.h"; sourceTree = "<group>"; };
E54E81FA1EB357BD00FFE8E1 /* ASPageTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPageTable.h; sourceTree = "<group>"; };
E54E81FB1EB357BD00FFE8E1 /* ASPageTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPageTable.m; sourceTree = "<group>"; };
E55D86311CA8A14000A0C26F /* ASLayoutElement.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASLayoutElement.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1101,6 +1103,7 @@
698371DA1E4379CD00437585 /* ASNodeController+Beta.m */,
25E327541C16819500A2170C /* ASPagerNode.h */,
25E327551C16819500A2170C /* ASPagerNode.m */,
E54E00711F1D3828000B30D7 /* ASPagerNode+Beta.h */,
A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */,
A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m */,
CCBBBF5C1EB161760069AA91 /* ASRangeManagingNode.h */,
Expand Down Expand Up @@ -1708,6 +1711,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
E54E00721F1D3828000B30D7 /* ASPagerNode+Beta.h in Headers */,
E5B225281F1790D6001E1431 /* ASHashing.h in Headers */,
CC034A131E649F1300626263 /* AsyncDisplayKit+IGListKitMethods.h in Headers */,
693A1DCA1ECC944E00D0C9D2 /* IGListAdapter+AsyncDisplayKit.h in Headers */,
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- [ASCollectionView] Add delegate bridging and index space translation for missing UICollectionViewLayout properties. [Scott Goodson](https://github.com/appleguy)
- [ASTextNode2] Add initial implementation for link handling. [Scott Goodson](https://github.com/appleguy) [#396](https://github.com/TextureGroup/Texture/pull/396)
- [ASTextNode2] Provide compile flag to globally enable new implementation of ASTextNode: ASTEXTNODE_EXPERIMENT_GLOBAL_ENABLE. [Scott Goodson](https://github.com/appleguy) [#396](https://github.com/TextureGroup/Texture/pull/410)
- Add ASCollectionGalleryLayoutDelegate - an async collection layout that makes same-size collections (e.g photo galleries, pagers, etc) fast and lightweight! [Huy Nguyen](https://github.com/nguyenhuy/) [#76](https://github.com/TextureGroup/Texture/pull/76)
- Add ASCollectionGalleryLayoutDelegate - an async collection layout that makes same-size collections (e.g photo galleries, pagers, etc) fast and lightweight! [Huy Nguyen](https://github.com/nguyenhuy/) [#76](https://github.com/TextureGroup/Texture/pull/76) [#451](https://github.com/TextureGroup/Texture/pull/451)

##2.3.5
- Fix an issue where inserting/deleting sections could lead to inconsistent supplementary element behavior. [Adlai Holler](https://github.com/Adlai-Holler)
Expand Down
19 changes: 19 additions & 0 deletions Source/ASPagerNode+Beta.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// ASPagerNode+Beta.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 <AsyncDisplayKit/ASPagerNode.h>

@interface ASPagerNode (Beta)

- (instancetype)initUsingAsyncCollectionLayout;

@end
24 changes: 23 additions & 1 deletion Source/ASPagerNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
//

#import <AsyncDisplayKit/ASPagerNode.h>
#import <AsyncDisplayKit/ASPagerNode+Beta.h>

#import <AsyncDisplayKit/ASCollectionGalleryLayoutDelegate.h>
#import <AsyncDisplayKit/ASCollectionNode+Beta.h>
#import <AsyncDisplayKit/ASDelegateProxy.h>
#import <AsyncDisplayKit/ASDisplayNode+FrameworkPrivate.h>
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
Expand All @@ -25,7 +29,7 @@
#import <AsyncDisplayKit/ASCollectionView+Undeprecated.h>
#import <AsyncDisplayKit/UIResponder+AsyncDisplayKit.h>

@interface ASPagerNode () <ASCollectionDataSource, ASCollectionDelegate, ASCollectionDelegateFlowLayout, ASDelegateProxyInterceptor>
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionDelegate, ASCollectionDelegateFlowLayout, ASDelegateProxyInterceptor, ASCollectionGalleryLayoutSizeProviding>
{
ASPagerFlowLayout *_flowLayout;

Expand Down Expand Up @@ -71,6 +75,16 @@ - (instancetype)initWithCollectionViewLayout:(ASPagerFlowLayout *)flowLayout;
return self;
}

- (instancetype)initUsingAsyncCollectionLayout
{
ASCollectionGalleryLayoutDelegate *layoutDelegate = [[ASCollectionGalleryLayoutDelegate alloc] initWithScrollableDirections:ASScrollDirectionHorizontalDirections];
self = [super initWithLayoutDelegate:layoutDelegate layoutFacilitator:nil];
if (self) {
layoutDelegate.sizeProvider = self;
}
return self;
}

#pragma mark - ASDisplayNode

- (void)didLoad
Expand Down Expand Up @@ -128,6 +142,14 @@ - (NSInteger)indexOfPageWithNode:(ASCellNode *)node
return indexPath.row;
}

#pragma mark - ASCollectionGalleryLayoutSizeProviding

- (CGSize)sizeForElements:(ASElementMap *)elements
{
ASDisplayNodeAssertMainThread();
return self.bounds.size;
}

#pragma mark - ASCollectionDataSource

- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
Expand Down
6 changes: 3 additions & 3 deletions Source/Details/ASCollectionFlowLayoutDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ - (instancetype)initWithScrollableDirections:(ASScrollDirection)scrollableDirect

- (ASScrollDirection)scrollableDirections
{
ASDisplayNodeAssertMainThread();
return _scrollableDirections;
}

- (id)additionalInfoForLayoutWithElements:(ASElementMap *)elements
{
ASDisplayNodeAssertMainThread();
return nil;
}

Expand All @@ -59,9 +61,7 @@ + (ASCollectionLayoutState *)calculateLayoutWithContext:(ASCollectionLayoutConte
ASElementMap *elements = context.elements;
NSMutableArray<ASCellNode *> *children = ASArrayByFlatMapping(elements.itemElements, ASCollectionElement *element, element.node);
if (children.count == 0) {
return [[ASCollectionLayoutState alloc] initWithContext:context
contentSize:CGSizeZero
elementToLayoutAttributesTable:[NSMapTable elementToLayoutAttributesTable]];
return [[ASCollectionLayoutState alloc] initWithContext:context];
}

ASStackLayoutSpec *stackSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal
Expand Down
21 changes: 20 additions & 1 deletion Source/Details/ASCollectionGalleryLayoutDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,25 @@
#import <AsyncDisplayKit/ASCollectionLayoutDelegate.h>
#import <AsyncDisplayKit/ASScrollDirection.h>

@class ASElementMap;

NS_ASSUME_NONNULL_BEGIN

@protocol ASCollectionGalleryLayoutSizeProviding <NSObject>

/**
* Returns the fixed size of each and every element.
*
* @discussion This method will only be called on main thread.
*
* @param elements All elements to be sized.
*
* @return The elements' size
*/
- (CGSize)sizeForElements:(ASElementMap *)elements;

@end

/**
* A thread-safe layout delegate that arranges items with the same size into a flow layout.
*
Expand All @@ -23,7 +40,9 @@ NS_ASSUME_NONNULL_BEGIN
AS_SUBCLASSING_RESTRICTED
@interface ASCollectionGalleryLayoutDelegate : NSObject <ASCollectionLayoutDelegate>

- (instancetype)initWithScrollableDirections:(ASScrollDirection)scrollableDirections itemSize:(CGSize)itemSize NS_DESIGNATED_INITIALIZER;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this one need to be deprecated?

Copy link
Member Author

@nguyenhuy nguyenhuy Jul 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it was merged last week (#76) and is still in Beta.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@property (nonatomic, weak) id<ASCollectionGalleryLayoutSizeProviding> sizeProvider;

- (instancetype)initWithScrollableDirections:(ASScrollDirection)scrollableDirections NS_DESIGNATED_INITIALIZER;

- (instancetype)init __unavailable;

Expand Down
27 changes: 17 additions & 10 deletions Source/Details/ASCollectionGalleryLayoutDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,40 +31,47 @@ @implementation ASCollectionGalleryLayoutDelegate {
CGSize _itemSize;
}

- (instancetype)initWithScrollableDirections:(ASScrollDirection)scrollableDirections itemSize:(CGSize)itemSize
- (instancetype)initWithScrollableDirections:(ASScrollDirection)scrollableDirections
{
self = [super init];
if (self) {
ASDisplayNodeAssertFalse(CGSizeEqualToSize(CGSizeZero, itemSize));
_scrollableDirections = scrollableDirections;
_itemSize = itemSize;
}
return self;
}

- (ASScrollDirection)scrollableDirections
{
ASDisplayNodeAssertMainThread();
return _scrollableDirections;
}

- (id)additionalInfoForLayoutWithElements:(ASElementMap *)elements
{
return [NSValue valueWithCGSize:_itemSize];
ASDisplayNodeAssertMainThread();
if (_sizeProvider == nil) {
return nil;
}

return [NSValue valueWithCGSize:[_sizeProvider sizeForElements:elements]];
}

+ (ASCollectionLayoutState *)calculateLayoutWithContext:(ASCollectionLayoutContext *)context
{
ASElementMap *elements = context.elements;
CGSize pageSize = context.viewportSize;
CGSize itemSize = ((NSValue *)context.additionalInfo).CGSizeValue;
ASScrollDirection scrollableDirections = context.scrollableDirections;

CGSize itemSize = context.additionalInfo ? ((NSValue *)context.additionalInfo).CGSizeValue : CGSizeZero;
if (CGSizeEqualToSize(CGSizeZero, itemSize)) {
return [[ASCollectionLayoutState alloc] initWithContext:context];
}

NSMutableArray<_ASGalleryLayoutItem *> *children = ASArrayByFlatMapping(elements.itemElements,
ASCollectionElement *element,
[[_ASGalleryLayoutItem alloc] initWithItemSize:itemSize collectionElement:element]);
ASCollectionElement *element,
[[_ASGalleryLayoutItem alloc] initWithItemSize:itemSize collectionElement:element]);
if (children.count == 0) {
return [[ASCollectionLayoutState alloc] initWithContext:context
contentSize:CGSizeZero
elementToLayoutAttributesTable:[NSMapTable weakToStrongObjectsMapTable]];
return [[ASCollectionLayoutState alloc] initWithContext:context];
}

// Use a stack spec to calculate layout content size and frames of all elements without actually measuring each element
Expand Down
1 change: 0 additions & 1 deletion Source/Details/ASCollectionLayoutContext.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ - (instancetype)initWithViewportSize:(CGSize)viewportSize
{
self = [super init];
if (self) {
ASDisplayNodeAssertTrue([layoutDelegateClass conformsToProtocol:@protocol(ASCollectionLayoutDelegate)]);
_viewportSize = viewportSize;
_scrollableDirections = scrollableDirections;
_elements = elements;
Expand Down
2 changes: 2 additions & 0 deletions Source/Details/ASCollectionLayoutDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ NS_ASSUME_NONNULL_BEGIN
* It will be available in the context parameter in +calculateLayoutWithContext:
*
* @return The scrollable directions.
*
* @discusstion This method will be called on main thread.
*/
- (ASScrollDirection)scrollableDirections;

Expand Down
7 changes: 7 additions & 0 deletions Source/Details/ASCollectionLayoutState.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ AS_SUBCLASSING_RESTRICTED
contentSize:(CGSize)contentSize
elementToLayoutAttributesTable:(NSMapTable<ASCollectionElement *, UICollectionViewLayoutAttributes *> *)table NS_DESIGNATED_INITIALIZER;

/**
* Convenience initializer. Returns an object with zero content size and an empty table.
*
* @param context The context used to calculate this object
*/
- (instancetype)initWithContext:(ASCollectionLayoutContext *)context;

/**
* Convenience initializer.
*
Expand Down
7 changes: 7 additions & 0 deletions Source/Details/ASCollectionLayoutState.mm
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ @implementation ASCollectionLayoutState {
ASPageToLayoutAttributesTable *_unmeasuredPageToLayoutAttributesTable;
}

- (instancetype)initWithContext:(ASCollectionLayoutContext *)context
{
return [self initWithContext:context
contentSize:CGSizeZero
elementToLayoutAttributesTable:[NSMapTable elementToLayoutAttributesTable]];
}

- (instancetype)initWithContext:(ASCollectionLayoutContext *)context
layout:(ASLayout *)layout
getElementBlock:(ASCollectionElement *(^)(ASLayout *))getElementBlock
Expand Down
5 changes: 1 addition & 4 deletions Source/Private/ASCollectionLayout.mm
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,9 @@ - (ASCollectionLayoutContext *)layoutContextWithElements:(ASElementMap *)element
+ (ASCollectionLayoutState *)calculateLayoutWithContext:(ASCollectionLayoutContext *)context
{
if (context.elements == nil) {
return [[ASCollectionLayoutState alloc] initWithContext:context
contentSize:CGSizeZero
elementToLayoutAttributesTable:[NSMapTable elementToLayoutAttributesTable]];
return [[ASCollectionLayoutState alloc] initWithContext:context];
}

ASDisplayNodeAssertTrue([context.layoutDelegateClass conformsToProtocol:@protocol(ASCollectionLayoutDelegate)]);
ASCollectionLayoutState *layout = [context.layoutDelegateClass calculateLayoutWithContext:context];
[context.layoutCache setLayout:layout forContext:context];

Expand Down
14 changes: 11 additions & 3 deletions examples/ASCollectionView/Sample/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#define ASYNC_COLLECTION_LAYOUT 0

@interface ViewController () <ASCollectionDataSource, ASCollectionDelegateFlowLayout>
@interface ViewController () <ASCollectionDataSource, ASCollectionDelegateFlowLayout, ASCollectionGalleryLayoutSizeProviding>

@property (nonatomic, strong) ASCollectionNode *collectionNode;
@property (nonatomic, strong) NSArray *data;
Expand All @@ -47,8 +47,8 @@ - (void)viewDidLoad
[super viewDidLoad];

#if ASYNC_COLLECTION_LAYOUT
id<ASCollectionLayoutDelegate> layoutDelegate = [[ASCollectionGalleryLayoutDelegate alloc] initWithScrollableDirections:ASScrollDirectionVerticalDirections
itemSize:CGSizeMake(180, 90)];
ASCollectionGalleryLayoutDelegate *layoutDelegate = [[ASCollectionGalleryLayoutDelegate alloc] initWithScrollableDirections:ASScrollDirectionVerticalDirections];
layoutDelegate.sizeProvider = self;
self.collectionNode = [[ASCollectionNode alloc] initWithLayoutDelegate:layoutDelegate layoutFacilitator:nil];
#else
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
Expand Down Expand Up @@ -108,6 +108,14 @@ - (void)reloadTapped
[self.collectionNode reloadData];
}

#pragma mark - ASCollectionGalleryLayoutSizeProviding

- (CGSize)sizeForElements:(ASElementMap *)elements
{
ASDisplayNodeAssertMainThread();
return CGSizeMake(180, 90);
}

#pragma mark - ASCollectionView Data Source

- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ - (instancetype)initWithNumberOfColumns:(NSInteger)numberOfColumns headerHeight:

- (ASScrollDirection)scrollableDirections
{
ASDisplayNodeAssertMainThread();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these and the below necessary? Seems a little strange to be in 'client' code? Leftover from testing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally added to tell whoever reading this example that these methods are called on main. Some rarely read the documentation :) I can definitely remove it if you think it's excessive.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good point!

return ASScrollDirectionVerticalDirections;
}

- (id)additionalInfoForLayoutWithElements:(ASElementMap *)elements
{
ASDisplayNodeAssertMainThread();
return _info;
}

Expand Down