Adds ASCollectionViewLayoutController and convenience CGRect/ASScrollDirection functions. Fixes default collection view range tuning parameters for Preload and Render ranges; values were flipped.

This commit is contained in:
Rene Cacheaux 2015-06-23 07:23:32 -05:00
commit 60e676a38a
9 changed files with 267 additions and 14 deletions

View File

@ -147,6 +147,10 @@
205F0E121B371BD7007741D0 /* ASScrollDirection.m in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E111B371BD7007741D0 /* ASScrollDirection.m */; };
205F0E191B37339C007741D0 /* ASAbstractLayoutController.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E171B37339C007741D0 /* ASAbstractLayoutController.h */; settings = {ATTRIBUTES = (Public, ); }; };
205F0E1A1B37339C007741D0 /* ASAbstractLayoutController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E181B37339C007741D0 /* ASAbstractLayoutController.mm */; };
205F0E1D1B373A2C007741D0 /* ASCollectionViewLayoutController.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */; settings = {ATTRIBUTES = (Public, ); }; };
205F0E1E1B373A2C007741D0 /* ASCollectionViewLayoutController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E1C1B373A2C007741D0 /* ASCollectionViewLayoutController.mm */; };
205F0E211B376416007741D0 /* CGRect+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */; };
205F0E221B376416007741D0 /* CGRect+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */; };
242995D31B29743C00090100 /* ASBasicImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */; };
2911485C1A77147A005D0878 /* ASControlNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2911485B1A77147A005D0878 /* ASControlNodeTests.m */; };
291B63FB1AA53A7A000A71B3 /* ASScrollDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 296A0A311A951715005ACEAA /* ASScrollDirection.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -329,6 +333,10 @@
205F0E111B371BD7007741D0 /* ASScrollDirection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollDirection.m; sourceTree = "<group>"; };
205F0E171B37339C007741D0 /* ASAbstractLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASAbstractLayoutController.h; sourceTree = "<group>"; };
205F0E181B37339C007741D0 /* ASAbstractLayoutController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASAbstractLayoutController.mm; sourceTree = "<group>"; };
205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutController.h; sourceTree = "<group>"; };
205F0E1C1B373A2C007741D0 /* ASCollectionViewLayoutController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionViewLayoutController.mm; sourceTree = "<group>"; };
205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CGRect+ASConvenience.h"; sourceTree = "<group>"; };
205F0E201B376416007741D0 /* CGRect+ASConvenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CGRect+ASConvenience.m"; sourceTree = "<group>"; };
242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASBasicImageDownloaderTests.m; sourceTree = "<group>"; };
2911485B1A77147A005D0878 /* ASControlNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASControlNodeTests.m; sourceTree = "<group>"; };
292C59991A956527007E5DD6 /* ASLayoutRangeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutRangeType.h; sourceTree = "<group>"; };
@ -554,6 +562,8 @@
054963481A1EA066000F8E56 /* ASBasicImageDownloader.mm */,
299DA1A71A828D2900162D41 /* ASBatchContext.h */,
299DA1A81A828D2900162D41 /* ASBatchContext.mm */,
205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */,
205F0E1C1B373A2C007741D0 /* ASCollectionViewLayoutController.mm */,
464052191A3F83C40061C0BA /* ASDataController.h */,
4640521A1A3F83C40061C0BA /* ASDataController.mm */,
05A6D05819D0EB64002DD95E /* ASDealloc2MainObject.h */,
@ -590,6 +600,8 @@
058D09F3195D050800B7D73C /* ASTextNodeWordKerner.h */,
058D09F4195D050800B7D73C /* ASTextNodeWordKerner.m */,
058D0A12195D050800B7D73C /* ASThread.h */,
205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */,
205F0E201B376416007741D0 /* CGRect+ASConvenience.m */,
058D09F5195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.h */,
058D09F6195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.m */,
058D09F7195D050800B7D73C /* Transactions */,
@ -728,6 +740,7 @@
6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */,
058D0A6D195D05EC00B7D73C /* _ASAsyncTransactionGroup.h in Headers */,
058D0A6E195D05EC00B7D73C /* _ASAsyncTransactionGroup.m in Headers */,
205F0E1D1B373A2C007741D0 /* ASCollectionViewLayoutController.h in Headers */,
058D0A6F195D05EC00B7D73C /* UIView+ASConvenience.h in Headers */,
058D0A70195D05EC00B7D73C /* UIView+ASConvenience.m in Headers */,
058D0A82195D060300B7D73C /* ASAssert.h in Headers */,
@ -754,6 +767,7 @@
058D0A79195D05F900B7D73C /* ASDisplayNode+DebugTiming.mm in Headers */,
058D0A7A195D05F900B7D73C /* ASDisplayNode+UIViewBridge.mm in Headers */,
2967F9E21AB0A5190072E4AB /* ASBasicImageDownloaderInternal.h in Headers */,
205F0E211B376416007741D0 /* CGRect+ASConvenience.h in Headers */,
058D0A7B195D05F900B7D73C /* ASDisplayNodeInternal.h in Headers */,
058D0A7C195D05F900B7D73C /* ASImageNode+CGExtras.h in Headers */,
058D0A7D195D05F900B7D73C /* ASImageNode+CGExtras.m in Headers */,
@ -932,6 +946,7 @@
058D0A1E195D050800B7D73C /* ASTextNodeShadower.m in Sources */,
058D0A18195D050800B7D73C /* _ASDisplayLayer.mm in Sources */,
058D0A2C195D050800B7D73C /* ASSentinel.m in Sources */,
205F0E221B376416007741D0 /* CGRect+ASConvenience.m in Sources */,
205F0E1A1B37339C007741D0 /* ASAbstractLayoutController.mm in Sources */,
464052211A3F83C40061C0BA /* ASDataController.mm in Sources */,
299DA1AA1A828D2900162D41 /* ASBatchContext.mm in Sources */,
@ -969,6 +984,7 @@
0516FA411A1563D200B4EBED /* ASMultiplexImageNode.mm in Sources */,
058D0A16195D050800B7D73C /* ASImageNode.mm in Sources */,
058D0A29195D050800B7D73C /* ASDisplayNode+DebugTiming.mm in Sources */,
205F0E1E1B373A2C007741D0 /* ASCollectionViewLayoutController.mm in Sources */,
058D0A22195D050800B7D73C /* _ASAsyncTransaction.m in Sources */,
055F1A3919ABD413004DAFF1 /* ASRangeController.mm in Sources */,
296A0A2F1A9516B2005ACEAA /* ASBatchFetching.m in Sources */,

View File

@ -9,7 +9,7 @@
#import "ASCollectionView.h"
#import "ASAssert.h"
#import "ASFlowLayoutController.h"
#import "ASCollectionViewLayoutController.h"
#import "ASRangeController.h"
#import "ASDataController.h"
#import "ASDisplayNodeInternal.h"
@ -109,7 +109,7 @@ static BOOL _isInterceptedSelector(SEL sel)
ASDataController *_dataController;
ASRangeController *_rangeController;
ASFlowLayoutController *_layoutController;
ASCollectionViewLayoutController *_layoutController;
BOOL _performingBatchUpdates;
NSMutableArray *_batchUpdateBlocks;
@ -143,9 +143,7 @@ static BOOL _isInterceptedSelector(SEL sel)
asyncDataFetchingEnabled = NO;
ASDisplayNodeAssert([layout asdk_isFlowLayout], @"only flow layouts are currently supported");
ASFlowLayoutDirection direction = (((UICollectionViewFlowLayout *)layout).scrollDirection == UICollectionViewScrollDirectionHorizontal) ? ASFlowLayoutDirectionHorizontal : ASFlowLayoutDirectionVertical;
_layoutController = [[ASFlowLayoutController alloc] initWithScrollOption:direction];
_layoutController = [[ASCollectionViewLayoutController alloc] initWithCollectionView:self];
_rangeController = [[ASRangeController alloc] init];
_rangeController.delegate = self;
@ -379,14 +377,14 @@ static BOOL _isInterceptedSelector(SEL sel)
ASScrollDirection scrollableDirections = [self scrollableDirections];
if (ASScrollDirectionContainsHorizontalDirection(scrollableDirections)) { // Can scroll horizontally.
if (scrollVelocity.x > 0) {
if (scrollVelocity.x >= 0) {
direction |= ASScrollDirectionRight;
} else {
direction |= ASScrollDirectionLeft;
}
}
if (ASScrollDirectionContainsVerticalDirection(scrollableDirections)) { // Can scroll vertically.
if (scrollVelocity.y > 0) {
if (scrollVelocity.y >= 0) {
direction |= ASScrollDirectionDown;
} else {
direction |= ASScrollDirectionUp;
@ -493,7 +491,7 @@ static BOOL _isInterceptedSelector(SEL sel)
{
CGSize restrainedSize = self.bounds.size;
if (_layoutController.layoutDirection == ASFlowLayoutDirectionHorizontal) {
if (ASScrollDirectionContainsHorizontalDirection([self scrollableDirections])) {
restrainedSize.width = FLT_MAX;
} else {
restrainedSize.height = FLT_MAX;

View File

@ -8,9 +8,7 @@
#import "ASAbstractLayoutController.h"
#include <map>
#include <vector>
#include <cassert>
#import "ASAssert.h"
@ -29,13 +27,13 @@
_tuningParameters = std::vector<ASRangeTuningParameters>(ASLayoutRangeTypeCount);
_tuningParameters[ASLayoutRangeTypePreload] = {
.leadingBufferScreenfuls = 2,
.trailingBufferScreenfuls = 1
};
_tuningParameters[ASLayoutRangeTypeRender] = {
.leadingBufferScreenfuls = 3,
.trailingBufferScreenfuls = 2
};
_tuningParameters[ASLayoutRangeTypeRender] = {
.leadingBufferScreenfuls = 2,
.trailingBufferScreenfuls = 1
};
return self;
}

View File

@ -0,0 +1,18 @@
/* Copyright (c) 2015-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.
*/
#import <AsyncDisplayKit/ASAbstractLayoutController.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
@class ASCollectionView;
@interface ASCollectionViewLayoutController : ASAbstractLayoutController
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView;
@end

View File

@ -0,0 +1,153 @@
/* Copyright (c) 2015-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.
*/
#import "ASCollectionViewLayoutController.h"
#include <vector>
#import "ASAssert.h"
#import "ASCollectionView.h"
#import "CGRect+ASConvenience.h"
struct ASDirectionalScreenfulBuffer {
CGFloat positiveDirection; // Positive relative to iOS Core Animation layer coordinate space.
CGFloat negativeDirection;
};
typedef struct ASDirectionalScreenfulBuffer ASDirectionalScreenfulBuffer;
ASDirectionalScreenfulBuffer ASDirectionalScreenfulBufferHorizontal(ASScrollDirection scrollDirection,
ASRangeTuningParameters rangeTuningParameters) {
ASDirectionalScreenfulBuffer horizontalBuffer = {0, 0};
BOOL movingRight = ASScrollDirectionContainsRight(scrollDirection);
horizontalBuffer.positiveDirection = movingRight ? rangeTuningParameters.leadingBufferScreenfuls :
rangeTuningParameters.trailingBufferScreenfuls;
horizontalBuffer.negativeDirection = movingRight ? rangeTuningParameters.trailingBufferScreenfuls :
rangeTuningParameters.leadingBufferScreenfuls;
return horizontalBuffer;
}
ASDirectionalScreenfulBuffer ASDirectionalScreenfulBufferVertical(ASScrollDirection scrollDirection,
ASRangeTuningParameters rangeTuningParameters) {
ASDirectionalScreenfulBuffer verticalBuffer = {0, 0};
BOOL movingDown = ASScrollDirectionContainsDown(scrollDirection);
verticalBuffer.positiveDirection = movingDown ? rangeTuningParameters.leadingBufferScreenfuls :
rangeTuningParameters.trailingBufferScreenfuls;
verticalBuffer.negativeDirection = movingDown ? rangeTuningParameters.trailingBufferScreenfuls :
rangeTuningParameters.leadingBufferScreenfuls;
return verticalBuffer;
}
struct ASRangeGeometry {
CGRect rangeBounds;
CGRect updateBounds;
};
typedef struct ASRangeGeometry ASRangeGeometry;
#pragma mark -
#pragma mark ASCollectionViewLayoutController
@interface ASCollectionViewLayoutController () {
ASCollectionView * __weak _collectionView;
std::vector<CGRect> _updateRangeBoundsIndexedByRangeType;
}
@end
@implementation ASCollectionViewLayoutController
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView {
if (!(self = [super init])) {
return nil;
}
_collectionView = collectionView;
_updateRangeBoundsIndexedByRangeType = std::vector<CGRect>(ASLayoutRangeTypeCount);
return self;
}
#pragma mark -
#pragma mark Index Paths in Range
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection
viewportSize:(CGSize)viewportSize
rangeType:(ASLayoutRangeType)rangeType {
ASRangeGeometry rangeGeometry = [self rangeGeometryWithScrollDirection:scrollDirection
collectionView:_collectionView
rangeTuningParameters:[self tuningParametersForRangeType:rangeType]];
_updateRangeBoundsIndexedByRangeType[rangeType] = rangeGeometry.updateBounds;
return [self indexPathsForItemsWithinRangeBounds:rangeGeometry.rangeBounds collectionView:_collectionView];
}
- (ASRangeGeometry)rangeGeometryWithScrollDirection:(ASScrollDirection)scrollDirection
collectionView:(ASCollectionView *)collectionView
rangeTuningParameters:(ASRangeTuningParameters)rangeTuningParameters {
CGRect rangeBounds = collectionView.bounds;
CGRect updateBounds = collectionView.bounds;
ASScrollDirection scrollableDirections = [collectionView scrollableDirections];
BOOL canScrollHorizontally = ASScrollDirectionContainsHorizontalDirection(scrollableDirections);
if (canScrollHorizontally) {
ASDirectionalScreenfulBuffer horizontalBuffer = ASDirectionalScreenfulBufferHorizontal(scrollDirection,
rangeTuningParameters);
rangeBounds = asdk_CGRectExpandHorizontally(rangeBounds,
horizontalBuffer.negativeDirection,
horizontalBuffer.positiveDirection);
// Update bounds is at most 95% of the next/previous screenful and at least half of tuning parameter value.
updateBounds = asdk_CGRectExpandHorizontally(updateBounds,
MIN(horizontalBuffer.negativeDirection * 0.5, 0.95),
MIN(horizontalBuffer.positiveDirection * 0.5, 0.95));
}
BOOL canScrollVertically = ASScrollDirectionContainsVerticalDirection(scrollableDirections);
if (canScrollVertically) {
ASDirectionalScreenfulBuffer verticalBuffer = ASDirectionalScreenfulBufferVertical(scrollDirection,
rangeTuningParameters);
rangeBounds = asdk_CGRectExpandVertically(rangeBounds,
verticalBuffer.negativeDirection,
verticalBuffer.positiveDirection);
// Update bounds is at most 95% of the next/previous screenful and at least half of tuning parameter value.
updateBounds = asdk_CGRectExpandVertically(updateBounds,
MIN(verticalBuffer.negativeDirection * 0.5, 0.95),
MIN(verticalBuffer.positiveDirection * 0.5, 0.95));
}
return {rangeBounds, updateBounds};
}
- (NSSet *)indexPathsForItemsWithinRangeBounds:(CGRect)rangeBounds collectionView:(ASCollectionView *)collectionView {
NSMutableSet *indexPathSet = [[NSMutableSet alloc] init];
NSArray *layoutAttributes = [collectionView.collectionViewLayout layoutAttributesForElementsInRect:rangeBounds];
for (UICollectionViewLayoutAttributes *la in layoutAttributes) {
[indexPathSet addObject:la.indexPath];
}
return indexPathSet;
}
#pragma mark -
#pragma mark Should Update Range
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths
viewportSize:(CGSize)viewportSize
rangeType:(ASLayoutRangeType)rangeType {
CGRect updateRangeBounds = _updateRangeBoundsIndexedByRangeType[rangeType];
if (CGRectIsEmpty(updateRangeBounds)) {
return YES;
}
CGRect currentBounds = _collectionView.bounds;
if (CGRectIsEmpty(currentBounds)) {
currentBounds = CGRectMake(0, 0, viewportSize.width, viewportSize.height);
}
if (CGRectContainsRect(updateRangeBounds, currentBounds)) {
return NO;
} else {
return YES;
}
}
@end

View File

@ -26,4 +26,9 @@ ASDISPLAYNODE_EXTERN_C_BEGIN
BOOL ASScrollDirectionContainsVerticalDirection(ASScrollDirection scrollDirection);
BOOL ASScrollDirectionContainsHorizontalDirection(ASScrollDirection scrollDirection);
BOOL ASScrollDirectionContainsRight(ASScrollDirection scrollDirection);
BOOL ASScrollDirectionContainsLeft(ASScrollDirection scrollDirection);
BOOL ASScrollDirectionContainsUp(ASScrollDirection scrollDirection);
BOOL ASScrollDirectionContainsDown(ASScrollDirection scrollDirection);
ASDISPLAYNODE_EXTERN_C_END

View File

@ -18,3 +18,19 @@ BOOL ASScrollDirectionContainsVerticalDirection(ASScrollDirection scrollDirectio
BOOL ASScrollDirectionContainsHorizontalDirection(ASScrollDirection scrollDirection) {
return (scrollDirection & ASScrollDirectionHorizontalDirections) != 0;
}
BOOL ASScrollDirectionContainsRight(ASScrollDirection scrollDirection) {
return (scrollDirection & ASScrollDirectionRight) != 0;
}
BOOL ASScrollDirectionContainsLeft(ASScrollDirection scrollDirection) {
return (scrollDirection & ASScrollDirectionLeft) != 0;
}
BOOL ASScrollDirectionContainsUp(ASScrollDirection scrollDirection) {
return (scrollDirection & ASScrollDirectionUp) != 0;
}
BOOL ASScrollDirectionContainsDown(ASScrollDirection scrollDirection) {
return (scrollDirection & ASScrollDirectionDown) != 0;
}

View File

@ -0,0 +1,18 @@
/* Copyright (c) 2015-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.
*/
#import <CoreGraphics/CoreGraphics.h>
#import "ASBaseDefines.h"
ASDISPLAYNODE_EXTERN_C_BEGIN
CGRect asdk_CGRectExpandHorizontally(CGRect rect, CGFloat negativeMultiplier, CGFloat positiveMultiplier);
CGRect asdk_CGRectExpandVertically(CGRect rect, CGFloat negativeMultiplier, CGFloat positiveMultiplier);
ASDISPLAYNODE_EXTERN_C_END

View File

@ -0,0 +1,31 @@
/* Copyright (c) 2015-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.
*/
#import "CGRect+ASConvenience.h"
CGRect asdk_CGRectExpandHorizontally(CGRect rect, CGFloat negativeMultiplier, CGFloat positiveMultiplier) {
CGFloat negativeDirectionWidth = negativeMultiplier * rect.size.width;
CGFloat positiveDirectionWidth = positiveMultiplier * rect.size.width;
CGFloat width = negativeDirectionWidth + rect.size.width + positiveDirectionWidth;
CGFloat originX = rect.origin.x - negativeDirectionWidth;
return CGRectMake(originX,
rect.origin.y,
width,
rect.size.height);
}
CGRect asdk_CGRectExpandVertically(CGRect rect, CGFloat negativeMultiplier, CGFloat positiveMultiplier) {
CGFloat negativeDirectionHeight = negativeMultiplier * rect.size.height;
CGFloat positiveDirectionHeight = positiveMultiplier * rect.size.height;
CGFloat height = negativeDirectionHeight + rect.size.height + positiveDirectionHeight;
CGFloat originY = rect.origin.y - negativeDirectionHeight;
return CGRectMake(rect.origin.x,
originY,
rect.size.width,
height);
}