[ASRangeController] Initial implementation of functional-style, ASInterfaceState-based range controller.

This commit is contained in:
Scott Goodson
2016-01-01 00:48:44 -08:00
parent 7a9cd1f930
commit b273f358f5
26 changed files with 382 additions and 187 deletions

View File

@@ -459,6 +459,7 @@
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.m */; };
DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; };
DE040EF91C2B40AC004692FF /* ASCollectionViewFlowLayoutInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */; settings = {ATTRIBUTES = (Public, ); }; };
DE0702FC1C3671E900D7DE62 /* libAsyncDisplayKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 058D09AC195D04C000B7D73C /* libAsyncDisplayKit.a */; };
DE6EA3221C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
DE8BEAC11C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = DE8BEABF1C2DF3FC00D57C12 /* ASDelegateProxy.h */; };
@@ -469,6 +470,10 @@
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
DECBD6E91BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
DECC2ECD1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */ = {isa = PBXBuildFile; fileRef = DECC2ECB1C35C1C600388446 /* ASRangeControllerBeta.h */; };
DECC2ECE1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */ = {isa = PBXBuildFile; fileRef = DECC2ECB1C35C1C600388446 /* ASRangeControllerBeta.h */; };
DECC2ECF1C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECC2ECC1C35C1C600388446 /* ASRangeControllerBeta.mm */; };
DECC2ED01C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECC2ECC1C35C1C600388446 /* ASRangeControllerBeta.mm */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -762,6 +767,8 @@
DE8BEAC01C2DF3FC00D57C12 /* ASDelegateProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDelegateProxy.m; sourceTree = "<group>"; };
DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; sourceTree = "<group>"; };
DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = "<group>"; };
DECC2ECB1C35C1C600388446 /* ASRangeControllerBeta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeControllerBeta.h; sourceTree = "<group>"; };
DECC2ECC1C35C1C600388446 /* ASRangeControllerBeta.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRangeControllerBeta.mm; sourceTree = "<group>"; };
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
FB07EABBCF28656C6297BC2D /* Pods-AsyncDisplayKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -771,6 +778,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DE0702FC1C3671E900D7DE62 /* libAsyncDisplayKit.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1029,6 +1037,8 @@
058D09E9195D050800B7D73C /* ASMutableAttributedStringBuilder.m */,
055F1A3619ABD413004DAFF1 /* ASRangeController.h */,
055F1A3719ABD413004DAFF1 /* ASRangeController.mm */,
DECC2ECB1C35C1C600388446 /* ASRangeControllerBeta.h */,
DECC2ECC1C35C1C600388446 /* ASRangeControllerBeta.mm */,
292C599C1A956527007E5DD6 /* ASRangeHandler.h */,
258FF4251C0D152600A83844 /* ASRangeHandlerVisible.h */,
258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */,
@@ -1315,6 +1325,7 @@
9C65A72A1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */,
292C599F1A956527007E5DD6 /* ASLayoutRangeType.h in Headers */,
257754B61BEE44CD00737CA5 /* ASEqualityHashHelpers.h in Headers */,
DECC2ECD1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */,
ACF6ED261B17843500DA7C62 /* ASLayoutSpec.h in Headers */,
ACF6ED4D1B17847A00DA7C62 /* ASLayoutSpecUtilities.h in Headers */,
AC026B6F1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */,
@@ -1373,6 +1384,7 @@
B350623C1B010EFD0018CF92 /* _ASAsyncTransaction.h in Headers */,
B350623E1B010EFD0018CF92 /* _ASAsyncTransactionContainer+Private.h in Headers */,
B350623F1B010EFD0018CF92 /* _ASAsyncTransactionContainer.h in Headers */,
DECC2ECE1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */,
254C6B7E1BF94DF4003EC431 /* ASTextKitTailTruncater.h in Headers */,
B35062411B010EFD0018CF92 /* _ASAsyncTransactionGroup.h in Headers */,
B35062491B010EFD0018CF92 /* _ASCoreAnimationExtras.h in Headers */,
@@ -1753,6 +1765,7 @@
257754BE1BEE458E00737CA5 /* ASTextKitHelpers.mm in Sources */,
257754A91BEE44CD00737CA5 /* ASTextKitContext.mm in Sources */,
ACF6ED501B17847A00DA7C62 /* ASStackPositionedLayout.mm in Sources */,
DECC2ECF1C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */,
ACF6ED521B17847A00DA7C62 /* ASStackUnpositionedLayout.mm in Sources */,
257754A61BEE44CD00737CA5 /* ASTextKitAttributes.mm in Sources */,
ACF6ED321B17843500DA7C62 /* ASStaticLayoutSpec.mm in Sources */,
@@ -1883,6 +1896,7 @@
9C8221981BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */,
34EFC7721B701D0300AD841F /* ASStackLayoutSpec.mm in Sources */,
34EFC7761B701D2A00AD841F /* ASStackPositionedLayout.mm in Sources */,
DECC2ED01C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */,
34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */,
AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */,
34EFC7741B701D0A00AD841F /* ASStaticLayoutSpec.mm in Sources */,

View File

@@ -14,6 +14,7 @@
#import "ASCollectionViewLayoutController.h"
#import "ASCollectionViewFlowLayoutInspector.h"
#import "ASDisplayNode+FrameworkPrivate.h"
#import "ASDisplayNode+Beta.h"
#import "ASInternalHelpers.h"
#import "ASRangeController.h"
#import "UICollectionViewLayout+ASConvenience.h"
@@ -150,9 +151,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
self.strongCollectionNode = collectionNode;
}
_layoutController = [[ASCollectionViewLayoutController alloc] initWithCollectionView:self];
_layoutController = [ASDisplayNode shouldUseNewRenderingRange] ?
[[ASCollectionViewLayoutControllerBeta alloc] initWithCollectionView:self] :
[[ASCollectionViewLayoutControllerStable alloc] initWithCollectionView:self];
_rangeController = [[ASRangeController alloc] init];
_rangeController = [ASDisplayNode shouldUseNewRenderingRange] ? [[ASRangeControllerBeta alloc] init]
: [[ASRangeControllerStable alloc] init];
_rangeController.dataSource = self;
_rangeController.delegate = self;
_rangeController.layoutController = _layoutController;
@@ -319,22 +323,22 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType
{
[_layoutController setTuningParameters:tuningParameters forRangeType:rangeType];
[_rangeController setTuningParameters:tuningParameters forRangeType:rangeType];
}
- (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType
{
return [_layoutController tuningParametersForRangeType:rangeType];
return [_rangeController tuningParametersForRangeType:rangeType];
}
- (ASRangeTuningParameters)rangeTuningParameters
{
return [self tuningParametersForRangeType:ASLayoutRangeTypeRender];
return [self tuningParametersForRangeType:ASLayoutRangeTypeDisplay];
}
- (void)setRangeTuningParameters:(ASRangeTuningParameters)tuningParameters
{
[self setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeRender];
[self setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeDisplay];
}
- (CGSize)calculatedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
@@ -775,6 +779,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
return [_dataController nodesAtIndexPaths:indexPaths];
}
- (ASDisplayNode *)rangeController:(ASRangeController *)rangeController nodeAtIndexPath:(NSIndexPath *)indexPath
{
return [_dataController nodeAtIndexPath:indexPath];
}
#pragma mark - ASRangeControllerDelegate
- (void)didBeginUpdatesInRangeController:(ASRangeController *)rangeController

View File

@@ -203,20 +203,26 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
ASDisplayNodeAssertMainThread();
static NSMutableSet *nodesToDisplay = nil;
static BOOL displayScheduled = NO;
static ASDN::RecursiveMutex displaySchedulerLock;
{
ASDN::MutexLocker l(displaySchedulerLock);
if (!nodesToDisplay) {
nodesToDisplay = [[NSMutableSet alloc] init];
}
[nodesToDisplay addObject:node];
}
if (!displayScheduled) {
displayScheduled = YES;
// It's essenital that any layout pass that is scheduled during the current
// runloop has a chance to be applied / scheduled, so always perform this after the current runloop.
dispatch_async(dispatch_get_main_queue(), ^{
ASDN::MutexLocker l(displaySchedulerLock);
displayScheduled = NO;
for (ASDisplayNode *node in nodesToDisplay) {
NSSet *displayingNodes = [nodesToDisplay copy];
nodesToDisplay = nil;
for (ASDisplayNode *node in displayingNodes) {
[node __recursivelyTriggerDisplayAndBlock:NO];
}
nodesToDisplay = nil;
});
}
}
@@ -1835,6 +1841,15 @@ static BOOL ShouldUseNewRenderingRange = NO;
});
}
- (void)recursivelySetInterfaceState:(ASInterfaceState)interfaceState
{
ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) {
node.interfaceState = interfaceState;
});
// FIXME: This should also be called in setInterfaceState: if it isn't being applied recursively.
[ASDisplayNode scheduleNodeForDisplay:self];
}
- (ASHierarchyState)hierarchyState
{
ASDN::MutexLocker l(_propertyLock);

View File

@@ -9,6 +9,7 @@
#import "ASPagerNode.h"
#import "ASDelegateProxy.h"
#import "ASDisplayNode+Subclasses.h"
#import "UICollectionViewLayout+ASConvenience.h"
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor>
{
@@ -34,7 +35,7 @@
- (instancetype)initWithCollectionViewLayout:(UICollectionViewFlowLayout *)flowLayout;
{
ASDisplayNodeAssert([flowLayout isKindOfClass:[UICollectionViewFlowLayout class]], @"ASPagerNode requires a flow layout.");
ASDisplayNodeAssert([flowLayout asdk_isFlowLayout], @"ASPagerNode requires a flow layout.");
self = [super initWithCollectionViewLayout:flowLayout];
if (self != nil) {
_flowLayout = flowLayout;
@@ -61,8 +62,8 @@
ASRangeTuningParameters preloadParams = { .leadingBufferScreenfuls = 2.0, .trailingBufferScreenfuls = 2.0 };
ASRangeTuningParameters renderParams = { .leadingBufferScreenfuls = 1.0, .trailingBufferScreenfuls = 1.0 };
[self setTuningParameters:preloadParams forRangeType:ASLayoutRangeTypePreload];
[self setTuningParameters:renderParams forRangeType:ASLayoutRangeTypeRender];
[self setTuningParameters:preloadParams forRangeType:ASLayoutRangeTypeFetchData];
[self setTuningParameters:renderParams forRangeType:ASLayoutRangeTypeDisplay];
}
#pragma mark - Helpers

View File

@@ -13,6 +13,7 @@
#import "ASChangeSetDataController.h"
#import "ASCollectionViewLayoutController.h"
#import "ASDelegateProxy.h"
#import "ASDisplayNode+Beta.h"
#import "ASDisplayNode+FrameworkPrivate.h"
#import "ASInternalHelpers.h"
#import "ASLayout.h"
@@ -85,7 +86,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
- (instancetype)_initWithTableView:(ASTableView *)tableView;
@end
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor> {
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate,
ASDataControllerSource, _ASTableViewCellDelegate,
ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor>
{
ASTableViewProxy *_proxyDataSource;
ASTableViewProxy *_proxyDelegate;
@@ -139,7 +143,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
{
_layoutController = [[ASFlowLayoutController alloc] initWithScrollOption:ASFlowLayoutDirectionVertical];
_rangeController = [[ASRangeController alloc] init];
_rangeController = [ASDisplayNode shouldUseNewRenderingRange] ? [[ASRangeControllerBeta alloc] init]
: [[ASRangeControllerStable alloc] init];
_rangeController.layoutController = _layoutController;
_rangeController.dataSource = self;
_rangeController.delegate = self;
@@ -317,12 +322,12 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
- (ASRangeTuningParameters)rangeTuningParameters
{
return [self tuningParametersForRangeType:ASLayoutRangeTypeRender];
return [self tuningParametersForRangeType:ASLayoutRangeTypeDisplay];
}
- (void)setRangeTuningParameters:(ASRangeTuningParameters)tuningParameters
{
[self setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeRender];
[self setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeDisplay];
}
- (ASCellNode *)nodeForRowAtIndexPath:(NSIndexPath *)indexPath
@@ -684,6 +689,11 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
return [_dataController nodesAtIndexPaths:indexPaths];
}
- (ASDisplayNode *)rangeController:(ASRangeController *)rangeController nodeAtIndexPath:(NSIndexPath *)indexPath
{
return [_dataController nodeAtIndexPath:indexPath];
}
- (CGSize)viewportSizeForRangeController:(ASRangeController *)rangeController
{
ASDisplayNodeAssertMainThread();

View File

@@ -13,10 +13,6 @@ NS_ASSUME_NONNULL_BEGIN
@interface ASAbstractLayoutController : NSObject <ASLayoutController>
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
- (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType;
@end
NS_ASSUME_NONNULL_END

View File

@@ -14,6 +14,7 @@
@interface ASAbstractLayoutController () {
std::vector<ASRangeTuningParameters> _tuningParameters;
CGSize _viewportSize;
}
@end
@@ -30,11 +31,11 @@
.leadingBufferScreenfuls = 0,
.trailingBufferScreenfuls = 0
};
_tuningParameters[ASLayoutRangeTypeRender] = {
_tuningParameters[ASLayoutRangeTypeDisplay] = {
.leadingBufferScreenfuls = 1.5,
.trailingBufferScreenfuls = 0.75
};
_tuningParameters[ASLayoutRangeTypePreload] = {
_tuningParameters[ASLayoutRangeTypeFetchData] = {
.leadingBufferScreenfuls = 3,
.trailingBufferScreenfuls = 2
};
@@ -60,16 +61,27 @@
#pragma mark - Abstract Index Path Range Support
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType
// FIXME: This method can be removed once ASRangeControllerBeta becomes the main version.
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths rangeType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertNotSupported();
return NO;
}
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertNotSupported();
return nil;
}
- (void)setViewportSize:(CGSize)viewportSize
{
_viewportSize = viewportSize;
}
- (CGSize)viewportSize
{
return _viewportSize;
}
@end

View File

@@ -19,4 +19,10 @@ NS_ASSUME_NONNULL_BEGIN
@end
@interface ASCollectionViewLayoutControllerStable : ASCollectionViewLayoutController
@end
@interface ASCollectionViewLayoutControllerBeta : ASCollectionViewLayoutController
@end
NS_ASSUME_NONNULL_END

View File

@@ -15,36 +15,6 @@
#import "CGRect+ASConvenience.h"
#import "UICollectionViewLayout+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;
@@ -57,9 +27,9 @@ typedef struct ASRangeGeometry ASRangeGeometry;
@interface ASCollectionViewLayoutController ()
{
@package
ASCollectionView * __weak _collectionView;
UICollectionViewLayout * __strong _collectionViewLayout;
std::vector<CGRect> _updateRangeBoundsIndexedByRangeType;
ASScrollDirection _scrollableDirections;
}
@end
@@ -75,63 +45,34 @@ typedef struct ASRangeGeometry ASRangeGeometry;
_scrollableDirections = [collectionView scrollableDirections];
_collectionView = collectionView;
_collectionViewLayout = [collectionView collectionViewLayout];
return self;
}
@end
@implementation ASCollectionViewLayoutControllerStable
{
std::vector<CGRect> _updateRangeBoundsIndexedByRangeType;
}
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView
{
if (!(self = [super initWithCollectionView:collectionView])) {
return nil;
}
_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
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeType:(ASLayoutRangeType)rangeType
{
ASRangeGeometry rangeGeometry = [self rangeGeometryWithScrollDirection:scrollDirection
rangeTuningParameters:[self tuningParametersForRangeType:rangeType]];
ASRangeTuningParameters tuningParameters = [self tuningParametersForRangeType:rangeType];
ASRangeGeometry rangeGeometry = [self rangeGeometryWithScrollDirection:scrollDirection tuningParameters:tuningParameters];
_updateRangeBoundsIndexedByRangeType[rangeType] = rangeGeometry.updateBounds;
return [self indexPathsForItemsWithinRangeBounds:rangeGeometry.rangeBounds];
}
- (ASRangeGeometry)rangeGeometryWithScrollDirection:(ASScrollDirection)scrollDirection
rangeTuningParameters:(ASRangeTuningParameters)rangeTuningParameters
{
CGRect rangeBounds = _collectionView.bounds;
CGRect updateBounds = _collectionView.bounds;
//scrollable directions can change for non-flow layouts
if ([_collectionViewLayout asdk_isFlowLayout] == NO) {
_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
{
NSMutableSet *indexPathSet = [[NSMutableSet alloc] init];
@@ -144,13 +85,31 @@ typedef struct ASRangeGeometry ASRangeGeometry;
return indexPathSet;
}
#pragma mark -
#pragma mark Should Update Range
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths
viewportSize:(CGSize)viewportSize
rangeType:(ASLayoutRangeType)rangeType
- (ASRangeGeometry)rangeGeometryWithScrollDirection:(ASScrollDirection)scrollDirection
tuningParameters:(ASRangeTuningParameters)tuningParameters
{
CGRect rangeBounds = _collectionView.bounds;
CGRect updateBounds = _collectionView.bounds;
// Scrollable directions can change for non-flow layouts
if ([_collectionViewLayout asdk_isFlowLayout] == NO) {
_scrollableDirections = [_collectionView scrollableDirections];
}
rangeBounds = CGRectExpandToRangeWithScrollableDirections(rangeBounds, tuningParameters, _scrollableDirections, scrollDirection);
ASRangeTuningParameters updateTuningParameters = tuningParameters;
updateTuningParameters.leadingBufferScreenfuls = MIN(updateTuningParameters.leadingBufferScreenfuls * 0.5, 0.95);
updateTuningParameters.trailingBufferScreenfuls = MIN(updateTuningParameters.trailingBufferScreenfuls * 0.5, 0.95);
updateBounds = CGRectExpandToRangeWithScrollableDirections(updateBounds, updateTuningParameters, _scrollableDirections, scrollDirection);
return {rangeBounds, updateBounds};
}
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths rangeType:(ASLayoutRangeType)rangeType
{
CGSize viewportSize = [self viewportSize];
CGRect updateRangeBounds = _updateRangeBoundsIndexedByRangeType[rangeType];
if (CGRectIsEmpty(updateRangeBounds)) {
return YES;
@@ -169,3 +128,40 @@ typedef struct ASRangeGeometry ASRangeGeometry;
}
@end
@implementation ASCollectionViewLayoutControllerBeta
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeType:(ASLayoutRangeType)rangeType
{
ASRangeTuningParameters tuningParameters = [self tuningParametersForRangeType:rangeType];
CGRect rangeBounds = [self rangeBoundsWithScrollDirection:scrollDirection rangeTuningParameters:tuningParameters];
return [self indexPathsForItemsWithinRangeBounds:rangeBounds];
}
- (NSSet *)indexPathsForItemsWithinRangeBounds:(CGRect)rangeBounds
{
NSArray *layoutAttributes = [_collectionViewLayout layoutAttributesForElementsInRect:rangeBounds];
NSMutableSet *indexPathSet = [NSMutableSet setWithCapacity:layoutAttributes.count];
for (UICollectionViewLayoutAttributes *la in layoutAttributes) {
//ASDisplayNodeAssert(![indexPathSet containsObject:la.indexPath], @"Shouldn't already contain indexPath");
ASDisplayNodeAssert(la.representedElementCategory != UICollectionElementCategoryDecorationView, @"UICollectionView decoration views are not supported by ASCollectionView");
[indexPathSet addObject:la.indexPath];
}
return indexPathSet;
}
- (CGRect)rangeBoundsWithScrollDirection:(ASScrollDirection)scrollDirection
rangeTuningParameters:(ASRangeTuningParameters)tuningParameters
{
CGRect rect = _collectionView.bounds;
// Scrollable directions can change for non-flow layouts
if ([_collectionViewLayout asdk_isFlowLayout] == NO) {
_scrollableDirections = [_collectionView scrollableDirections];
}
return CGRectExpandToRangeWithScrollableDirections(rect, tuningParameters, _scrollableDirections, scrollDirection);
}
@end

View File

@@ -39,7 +39,8 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
#pragma mark - Visible Indices
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType
// FIXME: This method can be removed once ASRangeControllerBeta becomes the main version.
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths rangeType:(ASLayoutRangeType)rangeType
{
if (!indexPaths.count || rangeType >= _rangesByType.size()) {
return NO;
@@ -73,10 +74,11 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
* IndexPath array for the element in the working range.
*/
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeType:(ASLayoutRangeType)rangeType
{
CGFloat viewportScreenMetric;
ASScrollDirection leadingDirection;
CGSize viewportSize = [self viewportSize];
if (_layoutDirection == ASFlowLayoutDirectionHorizontal) {
ASDisplayNodeAssert(scrollDirection == ASScrollDirectionNone || scrollDirection == ASScrollDirectionLeft || scrollDirection == ASScrollDirectionRight, @"Invalid scroll direction");

View File

@@ -28,11 +28,14 @@ typedef struct {
*
* Defaults to a trailing buffer of one screenful and a leading buffer of two screenfuls.
*/
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
- (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType;
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray<NSIndexPath *> *)indexPaths viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType;
// FIXME: This method can be removed once ASRangeControllerBeta becomes the main version.
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray<NSIndexPath *> *)indexPaths rangeType:(ASLayoutRangeType)rangeType;
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType;
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeType:(ASLayoutRangeType)rangeType;
@optional
@@ -46,6 +49,9 @@ typedef struct {
- (void)setVisibleNodeIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;
- (void)setViewportSize:(CGSize)viewportSize;
- (CGSize)viewportSize;
@end
NS_ASSUME_NONNULL_END

View File

@@ -10,7 +10,10 @@
typedef NS_ENUM(NSInteger, ASLayoutRangeType) {
ASLayoutRangeTypeVisible = 0,
ASLayoutRangeTypeRender,
ASLayoutRangeTypePreload,
ASLayoutRangeTypeDisplay,
ASLayoutRangeTypeFetchData,
ASLayoutRangeTypeCount
};
#define ASLayoutRangeTypeRender ASLayoutRangeTypeDisplay
#define ASLayoutRangeTypePreload ASLayoutRangeTypeFetchData

View File

@@ -26,6 +26,11 @@ NS_ASSUME_NONNULL_BEGIN
* This includes cancelling those asynchronous operations as cells fall outside of the working ranges.
*/
@interface ASRangeController : ASDealloc2MainObject <ASDataControllerDelegate>
{
id<ASLayoutController> _layoutController;
__weak id<ASRangeControllerDataSource> _dataSource;
__weak id<ASRangeControllerDelegate> _delegate;
}
/**
* Notify the range controller that the visible range has been updated.
@@ -46,6 +51,9 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)node;
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
- (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType;
/**
* An object that describes the layout behavior of the ranged component (table view, collection view, etc.)
*
@@ -66,6 +74,12 @@ NS_ASSUME_NONNULL_BEGIN
@end
@interface ASRangeControllerStable : ASRangeController
@end
@interface ASRangeControllerBeta : ASRangeController
@end
/**
* Data source for ASRangeController.
*
@@ -88,15 +102,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (CGSize)viewportSizeForRangeController:(ASRangeController *)rangeController;
/**
* Fetch nodes at specific index paths.
*
* @param rangeController Sender.
*
* @param indexPaths Index paths.
*/
- (NSArray *)rangeController:(ASRangeController *)rangeController nodesAtIndexPaths:(NSArray *)indexPaths;
- (ASDisplayNode *)rangeController:(ASRangeController *)rangeController nodeAtIndexPath:(NSIndexPath *)indexPath;
@end
/**

View File

@@ -15,8 +15,33 @@
#import "ASRangeHandlerRender.h"
#import "ASRangeHandlerPreload.h"
#import "ASInternalHelpers.h"
#import "ASLayoutController.h"
#import "ASLayoutRangeType.h"
@interface ASRangeController () {
@implementation ASRangeController
- (void)visibleNodeIndexPathsDidChangeWithScrollDirection:(ASScrollDirection)scrollDirection
{
}
- (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)node
{
}
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType
{
[_layoutController setTuningParameters:tuningParameters forRangeType:rangeType];
}
- (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType
{
return [_layoutController tuningParametersForRangeType:rangeType];
}
@end
@interface ASRangeControllerStable ()
{
BOOL _rangeIsValid;
// keys should be ASLayoutRangeTypes and values NSSets containing NSIndexPaths
@@ -29,19 +54,21 @@
@end
@implementation ASRangeController
@implementation ASRangeControllerStable
- (instancetype)init
{
if (!(self = [super init])) {
return nil;
}
- (instancetype)init {
self = [super init];
if (self != nil) {
_rangeIsValid = YES;
_rangeTypeIndexPaths = [NSMutableDictionary dictionary];
_rangeTypeHandlers = @{
@(ASLayoutRangeTypeVisible): [[ASRangeHandlerVisible alloc] init],
@(ASLayoutRangeTypeRender): [[ASRangeHandlerRender alloc] init],
@(ASLayoutRangeTypePreload): [[ASRangeHandlerPreload alloc] init],
@(ASLayoutRangeTypeVisible) : [[ASRangeHandlerVisible alloc] init],
@(ASLayoutRangeTypeDisplay) : [[ASRangeHandlerRender alloc] init],
@(ASLayoutRangeTypeFetchData): [[ASRangeHandlerPreload alloc] init],
};
}
return self;
}
@@ -111,6 +138,7 @@
NSSet *visibleNodePathsSet = [NSSet setWithArray:visibleNodePaths];
CGSize viewportSize = [_dataSource viewportSizeForRangeController:self];
[_layoutController setViewportSize:viewportSize];
// the layout controller needs to know what the current visible indices are to calculate range offsets
if ([_layoutController respondsToSelector:@selector(setVisibleNodeIndexPaths:)]) {
@@ -124,10 +152,8 @@
// this delegate decide what happens when a node is added or removed from a range
id<ASRangeHandler> rangeHandler = _rangeTypeHandlers[rangeKey];
if (!_rangeIsValid || [_layoutController shouldUpdateForVisibleIndexPaths:visibleNodePaths viewportSize:viewportSize rangeType:rangeType]) {
NSSet *indexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
viewportSize:viewportSize
rangeType:rangeType];
if (!_rangeIsValid || [_layoutController shouldUpdateForVisibleIndexPaths:visibleNodePaths rangeType:rangeType]) {
NSSet *indexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:rangeType];
// Notify to remove indexpaths that are leftover that are not visible or included in the _layoutController calculated paths
// This value may be nil for the first call of this method.
@@ -172,7 +198,7 @@
- (BOOL)shouldSkipVisibleNodesForRangeType:(ASLayoutRangeType)rangeType
{
return rangeType == ASLayoutRangeTypeRender;
return rangeType == ASLayoutRangeTypeDisplay;
}
#pragma mark - ASDataControllerDelegete

View File

@@ -72,26 +72,19 @@
}
CGSize viewportSize = [_dataSource viewportSizeForRangeController:self];
[_layoutController setViewportSize:viewportSize];
// the layout controller needs to know what the current visible indices are to calculate range offsets
if ([_layoutController respondsToSelector:@selector(setVisibleNodeIndexPaths:)]) {
[_layoutController setVisibleNodeIndexPaths:visibleNodePaths];
}
NSSet *fetchDataIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
viewportSize:viewportSize
rangeType:ASLayoutRangeTypeFetchData];
NSSet *fetchDataIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeFetchData];
NSSet *displayIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeDisplay];
NSSet *visibleIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeVisible];
NSSet *displayIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
viewportSize:viewportSize
rangeType:ASLayoutRangeTypeDisplay];
NSSet *visibleIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
viewportSize:viewportSize
rangeType:ASLayoutRangeTypeVisible];
NSSet *visibleNodePathsSet = [NSSet setWithArray:visibleNodePaths];
// NSLog(@"visible sets are equal: %d", [visibleIndexPaths isEqualToSet:visibleNodePathsSet]);
//NSSet *visibleNodePathsSet = [NSSet setWithArray:visibleNodePaths];
//NSLog(@"visible sets are equal: %d", [visibleIndexPaths isEqualToSet:visibleNodePathsSet]);
// Typically the fetchDataIndexPaths will be the largest, and be a superset of the others, though it may be disjoint.
NSMutableSet *allIndexPaths = [fetchDataIndexPaths mutableCopy];

View File

@@ -14,13 +14,13 @@
- (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypePreload, @"Preload delegate should not handle other ranges");
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeFetchData, @"Preload delegate should not handle other ranges");
[node enterInterfaceState:ASInterfaceStateFetchData];
}
- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypePreload, @"Preload delegate should not handle other ranges");
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeFetchData, @"Preload delegate should not handle other ranges");
[node exitInterfaceState:ASInterfaceStateFetchData];
}

View File

@@ -44,7 +44,7 @@
if (![ASDisplayNode shouldUseNewRenderingRange]) {
for (CALayer *layer in [self.workingWindow.layer.sublayers copy]) {
ASDisplayNode *node = layer.asyncdisplaykit_node;
[self node:node exitedRangeOfType:ASLayoutRangeTypeRender];
[self node:node exitedRangeOfType:ASLayoutRangeTypeDisplay];
}
}
}
@@ -52,7 +52,7 @@
- (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeRender, @"Render delegate should not handle other ranges");
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeDisplay, @"Render delegate should not handle other ranges");
// If a node had previously been onscreen but now is only in the working range,
// ensure its view is not orphaned in a UITableViewCell in the reuse pool.
@@ -64,6 +64,7 @@
[node enterInterfaceState:ASInterfaceStateDisplay];
ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled");
if ([ASDisplayNode shouldUseNewRenderingRange]) {
[node recursivelyEnsureDisplaySynchronously:NO];
} else {
@@ -79,7 +80,7 @@
- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeRender, @"Render delegate should not handle other ranges");
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeDisplay, @"Render delegate should not handle other ranges");
// This code is tricky. There are several possible states a node can be in when it reaches this point.
// 1. Layer-backed vs view-backed nodes. AS of this writing, only ASCellNodes arrive here, which are always view-backed —
@@ -101,6 +102,8 @@
// The node calls clearCurrentContents and suspends display
[node exitInterfaceState:ASInterfaceStateDisplay];
ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled");
if ([ASDisplayNode shouldUseNewRenderingRange]) {
if (![node isLayerBacked]) {
[node.view removeFromSuperview];

View File

@@ -10,13 +10,16 @@
#import <CoreGraphics/CoreGraphics.h>
#import "ASBaseDefines.h"
#import "ASLayoutController.h"
NS_ASSUME_NONNULL_BEGIN
ASDISPLAYNODE_EXTERN_C_BEGIN
CGRect asdk_CGRectExpandHorizontally(CGRect rect, CGFloat negativeMultiplier, CGFloat positiveMultiplier);
CGRect asdk_CGRectExpandVertically(CGRect rect, CGFloat negativeMultiplier, CGFloat positiveMultiplier);
CGRect CGRectExpandToRangeWithScrollableDirections(CGRect rect,
ASRangeTuningParameters tuningParameters,
ASScrollDirection scrollableDirections,
ASScrollDirection scrollDirection);
ASDISPLAYNODE_EXTERN_C_END

View File

@@ -7,25 +7,74 @@
*/
#import "CGRect+ASConvenience.h"
#import "ASScrollDirection.h"
#import "ASLayoutController.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);
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;
}
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);
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;
}
CGRect CGRectExpandHorizontally(CGRect rect, ASDirectionalScreenfulBuffer buffer)
{
CGFloat negativeDirectionWidth = buffer.negativeDirection * rect.size.width;
CGFloat positiveDirectionWidth = buffer.positiveDirection * rect.size.width;
rect.size.width = negativeDirectionWidth + rect.size.width + positiveDirectionWidth;
rect.origin.x -= negativeDirectionWidth;
return rect;
}
CGRect CGRectExpandVertically(CGRect rect, ASDirectionalScreenfulBuffer buffer)
{
CGFloat negativeDirectionHeight = buffer.negativeDirection * rect.size.height;
CGFloat positiveDirectionHeight = buffer.positiveDirection * rect.size.height;
rect.size.height = negativeDirectionHeight + rect.size.height + positiveDirectionHeight;
rect.origin.y -= negativeDirectionHeight;
return rect;
}
CGRect CGRectExpandToRangeWithScrollableDirections(CGRect rect, ASRangeTuningParameters tuningParameters,
ASScrollDirection scrollableDirections, ASScrollDirection scrollDirection)
{
// Can scroll horizontally - expand the range appropriately
if (ASScrollDirectionContainsHorizontalDirection(scrollableDirections)) {
ASDirectionalScreenfulBuffer horizontalBuffer = ASDirectionalScreenfulBufferHorizontal(scrollDirection, tuningParameters);
rect = CGRectExpandHorizontally(rect, horizontalBuffer);
}
// Can scroll vertically - expand the range appropriately
if (ASScrollDirectionContainsVerticalDirection(scrollableDirections)) {
ASDirectionalScreenfulBuffer verticalBuffer = ASDirectionalScreenfulBufferVertical(scrollDirection, tuningParameters);
rect = CGRectExpandVertically(rect, verticalBuffer);
}
return rect;
}

View File

@@ -10,8 +10,9 @@
@implementation UICollectionViewLayout (ASConvenience)
- (BOOL)asdk_isFlowLayout {
return [self isKindOfClass:UICollectionViewFlowLayout.class];
- (BOOL)asdk_isFlowLayout
{
return [self isKindOfClass:[UICollectionViewFlowLayout class]];
}
@end

View File

@@ -60,6 +60,7 @@ typedef NS_OPTIONS(NSUInteger, ASHierarchyState)
// These methods are recursive, and either union or remove the provided interfaceState to all sub-elements.
- (void)enterInterfaceState:(ASInterfaceState)interfaceState;
- (void)exitInterfaceState:(ASInterfaceState)interfaceState;
- (void)recursivelySetInterfaceState:(ASInterfaceState)interfaceState;
// These methods are recursive, and either union or remove the provided hierarchyState to all sub-elements.
- (void)enterHierarchyState:(ASHierarchyState)hierarchyState;

View File

@@ -250,7 +250,8 @@
_messageToViewOrLayer(setNeedsDisplay);
if ([ASDisplayNode shouldUseNewRenderingRange]) {
if (_layer && !self.isSynchronous) {
BOOL shouldDisplay = ((_interfaceState & ASInterfaceStateDisplay) == ASInterfaceStateDisplay);
if (_layer && !_flags.synchronous && shouldDisplay) {
[ASDisplayNode scheduleNodeForDisplay:self];
}
}

View File

@@ -13,10 +13,15 @@
#import "ViewController.h"
#import <AsyncDisplayKit/ASDisplayNode.h>
#import <AsyncDisplayKit/ASDisplayNode+Beta.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[ASDisplayNode setShouldUseNewRenderingRange:YES];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];

View File

@@ -51,7 +51,7 @@
ASRangeTuningParameters rangeTuningParameters;
rangeTuningParameters.leadingBufferScreenfuls = 1.0;
rangeTuningParameters.trailingBufferScreenfuls = 0.5;
[_tableNode.view setTuningParameters:rangeTuningParameters forRangeType:ASLayoutRangeTypeRender];
[_tableNode.view setTuningParameters:rangeTuningParameters forRangeType:ASLayoutRangeTypeDisplay];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

View File

@@ -9,6 +9,9 @@
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface RandomCoreGraphicsNode : ASCellNode
{
ASTextNode *_indexPathTextNode;
}
@property (nonatomic) NSIndexPath *indexPath;

View File

@@ -42,6 +42,37 @@
CGColorSpaceRelease(colorSpace);
}
- (instancetype)init
{
if (!(self = [super init])) {
return nil;
}
_indexPathTextNode = [[ASTextNode alloc] init];
[self addSubnode:_indexPathTextNode];
return self;
}
- (void)setIndexPath:(NSIndexPath *)indexPath
{
_indexPath = indexPath;
_indexPathTextNode.attributedString = [[NSAttributedString alloc] initWithString:[indexPath description] attributes:nil];
}
//- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
//{
// ASStackLayoutSpec *stackSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[_indexPathTextNode]];
// stackSpec.flexGrow = YES;
// return stackSpec;
//}
- (void)layout
{
_indexPathTextNode.frame = self.bounds;
[super layout];
}
#if 0
- (void)fetchData
{