mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
[ASRangeController] Initial implementation of functional-style, ASInterfaceState-based range controller.
This commit is contained in:
@@ -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 */,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -203,20 +203,26 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
ASDisplayNodeAssertMainThread();
|
||||
static NSMutableSet *nodesToDisplay = nil;
|
||||
static BOOL displayScheduled = NO;
|
||||
if (!nodesToDisplay) {
|
||||
nodesToDisplay = [[NSMutableSet alloc] init];
|
||||
static ASDN::RecursiveMutex displaySchedulerLock;
|
||||
{
|
||||
ASDN::MutexLocker l(displaySchedulerLock);
|
||||
if (!nodesToDisplay) {
|
||||
nodesToDisplay = [[NSMutableSet alloc] init];
|
||||
}
|
||||
[nodesToDisplay addObject:node];
|
||||
}
|
||||
[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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -19,4 +19,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@end
|
||||
|
||||
@interface ASCollectionViewLayoutControllerStable : ASCollectionViewLayoutController
|
||||
@end
|
||||
|
||||
@interface ASCollectionViewLayoutControllerBeta : ASCollectionViewLayoutController
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
|
||||
typedef NS_ENUM(NSInteger, ASLayoutRangeType) {
|
||||
ASLayoutRangeTypeVisible = 0,
|
||||
ASLayoutRangeTypeRender,
|
||||
ASLayoutRangeTypePreload,
|
||||
ASLayoutRangeTypeDisplay,
|
||||
ASLayoutRangeTypeFetchData,
|
||||
ASLayoutRangeTypeCount
|
||||
};
|
||||
|
||||
#define ASLayoutRangeTypeRender ASLayoutRangeTypeDisplay
|
||||
#define ASLayoutRangeTypePreload ASLayoutRangeTypeFetchData
|
||||
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,34 +15,61 @@
|
||||
#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
|
||||
NSMutableDictionary *_rangeTypeIndexPaths;
|
||||
NSDictionary *_rangeTypeHandlers;
|
||||
BOOL _queuedRangeUpdate;
|
||||
|
||||
|
||||
ASScrollDirection _scrollDirection;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASRangeController
|
||||
@implementation ASRangeControllerStable
|
||||
|
||||
- (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],
|
||||
};
|
||||
- (instancetype)init
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
_rangeIsValid = YES;
|
||||
_rangeTypeIndexPaths = [NSMutableDictionary dictionary];
|
||||
_rangeTypeHandlers = @{
|
||||
@(ASLayoutRangeTypeVisible) : [[ASRangeHandlerVisible alloc] init],
|
||||
@(ASLayoutRangeTypeDisplay) : [[ASRangeHandlerRender alloc] init],
|
||||
@(ASLayoutRangeTypeFetchData): [[ASRangeHandlerPreload alloc] init],
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -111,12 +138,13 @@
|
||||
|
||||
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:)]) {
|
||||
[_layoutController setVisibleNodeIndexPaths:visibleNodePaths];
|
||||
}
|
||||
|
||||
|
||||
for (NSInteger i = 0; i < ASLayoutRangeTypeCount; i++) {
|
||||
ASLayoutRangeType rangeType = (ASLayoutRangeType)i;
|
||||
id rangeKey = @(rangeType);
|
||||
@@ -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
|
||||
|
||||
@@ -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 *displayIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
|
||||
viewportSize:viewportSize
|
||||
rangeType:ASLayoutRangeTypeDisplay];
|
||||
|
||||
NSSet *visibleIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
|
||||
viewportSize:viewportSize
|
||||
rangeType:ASLayoutRangeTypeVisible];
|
||||
NSSet *fetchDataIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeFetchData];
|
||||
NSSet *displayIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeDisplay];
|
||||
NSSet *visibleIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection 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];
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
|
||||
@implementation UICollectionViewLayout (ASConvenience)
|
||||
|
||||
- (BOOL)asdk_isFlowLayout {
|
||||
return [self isKindOfClass:UICollectionViewFlowLayout.class];
|
||||
- (BOOL)asdk_isFlowLayout
|
||||
{
|
||||
return [self isKindOfClass:[UICollectionViewFlowLayout class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
|
||||
@interface RandomCoreGraphicsNode : ASCellNode
|
||||
{
|
||||
ASTextNode *_indexPathTextNode;
|
||||
}
|
||||
|
||||
@property (nonatomic) NSIndexPath *indexPath;
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user