mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-15 16:36:36 +00:00
Implement async transition
This commit is contained in:
parent
cdd1bd1e39
commit
fa8f2f4429
@ -514,6 +514,8 @@
|
|||||||
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
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 */; };
|
DECBD6E91BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
||||||
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
||||||
|
E52405B31C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = E52405B21C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm */; };
|
||||||
|
E52405B51C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E52405B41C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h */; };
|
||||||
E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; };
|
E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; };
|
||||||
E5711A2E1C840C96009619D4 /* ASIndexedNodeContext.m in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */; };
|
E5711A2E1C840C96009619D4 /* ASIndexedNodeContext.m in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */; };
|
||||||
@ -845,6 +847,8 @@
|
|||||||
DEC146B51C37A16A004A0EE7 /* ASCollectionInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASCollectionInternal.m; path = Details/ASCollectionInternal.m; sourceTree = "<group>"; };
|
DEC146B51C37A16A004A0EE7 /* ASCollectionInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASCollectionInternal.m; path = Details/ASCollectionInternal.m; sourceTree = "<group>"; };
|
||||||
DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; 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>"; };
|
DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = "<group>"; };
|
||||||
|
E52405B21C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeLayoutContext.mm; sourceTree = "<group>"; };
|
||||||
|
E52405B41C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayNodeLayoutContext.h; sourceTree = "<group>"; };
|
||||||
E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIndexedNodeContext.h; sourceTree = "<group>"; };
|
E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIndexedNodeContext.h; sourceTree = "<group>"; };
|
||||||
E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIndexedNodeContext.m; sourceTree = "<group>"; };
|
E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIndexedNodeContext.m; sourceTree = "<group>"; };
|
||||||
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@ -1192,6 +1196,8 @@
|
|||||||
058D0A0A195D050800B7D73C /* ASDisplayNode+DebugTiming.mm */,
|
058D0A0A195D050800B7D73C /* ASDisplayNode+DebugTiming.mm */,
|
||||||
058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */,
|
058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */,
|
||||||
DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */,
|
DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */,
|
||||||
|
E52405B41C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h */,
|
||||||
|
E52405B21C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm */,
|
||||||
058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */,
|
058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */,
|
||||||
058D0A0D195D050800B7D73C /* ASImageNode+CGExtras.h */,
|
058D0A0D195D050800B7D73C /* ASImageNode+CGExtras.h */,
|
||||||
058D0A0E195D050800B7D73C /* ASImageNode+CGExtras.m */,
|
058D0A0E195D050800B7D73C /* ASImageNode+CGExtras.m */,
|
||||||
@ -1453,6 +1459,7 @@
|
|||||||
055B9FA81A1C154B00035D6D /* ASNetworkImageNode.h in Headers */,
|
055B9FA81A1C154B00035D6D /* ASNetworkImageNode.h in Headers */,
|
||||||
ACF6ED2B1B17843500DA7C62 /* ASOverlayLayoutSpec.h in Headers */,
|
ACF6ED2B1B17843500DA7C62 /* ASOverlayLayoutSpec.h in Headers */,
|
||||||
055F1A3819ABD413004DAFF1 /* ASRangeController.h in Headers */,
|
055F1A3819ABD413004DAFF1 /* ASRangeController.h in Headers */,
|
||||||
|
E52405B51C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h in Headers */,
|
||||||
ACF6ED2D1B17843500DA7C62 /* ASRatioLayoutSpec.h in Headers */,
|
ACF6ED2D1B17843500DA7C62 /* ASRatioLayoutSpec.h in Headers */,
|
||||||
AC47D9451B3BB41900AAEE9D /* ASRelativeSize.h in Headers */,
|
AC47D9451B3BB41900AAEE9D /* ASRelativeSize.h in Headers */,
|
||||||
291B63FB1AA53A7A000A71B3 /* ASScrollDirection.h in Headers */,
|
291B63FB1AA53A7A000A71B3 /* ASScrollDirection.h in Headers */,
|
||||||
@ -1675,6 +1682,7 @@
|
|||||||
058D09B9195D04C000B7D73C /* Frameworks */,
|
058D09B9195D04C000B7D73C /* Frameworks */,
|
||||||
058D09BA195D04C000B7D73C /* Resources */,
|
058D09BA195D04C000B7D73C /* Resources */,
|
||||||
3B9D88CDF51B429C8409E4B6 /* Copy Pods Resources */,
|
3B9D88CDF51B429C8409E4B6 /* Copy Pods Resources */,
|
||||||
|
B130AB1AC0A1E5162E211C19 /* Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -1804,6 +1812,21 @@
|
|||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n";
|
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
|
B130AB1AC0A1E5162E211C19 /* Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Embed Pods Frameworks";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@ -1885,6 +1908,7 @@
|
|||||||
ACF6ED2C1B17843500DA7C62 /* ASOverlayLayoutSpec.mm in Sources */,
|
ACF6ED2C1B17843500DA7C62 /* ASOverlayLayoutSpec.mm in Sources */,
|
||||||
0442850F1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm in Sources */,
|
0442850F1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm in Sources */,
|
||||||
257754921BED28F300737CA5 /* ASEqualityHashHelpers.mm in Sources */,
|
257754921BED28F300737CA5 /* ASEqualityHashHelpers.mm in Sources */,
|
||||||
|
E52405B31C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm in Sources */,
|
||||||
257754AB1BEE44CD00737CA5 /* ASTextKitEntityAttribute.m in Sources */,
|
257754AB1BEE44CD00737CA5 /* ASTextKitEntityAttribute.m in Sources */,
|
||||||
055F1A3919ABD413004DAFF1 /* ASRangeController.mm in Sources */,
|
055F1A3919ABD413004DAFF1 /* ASRangeController.mm in Sources */,
|
||||||
044285091BAA63FE00D16268 /* ASBatchFetching.m in Sources */,
|
044285091BAA63FE00D16268 /* ASBatchFetching.m in Sources */,
|
||||||
|
@ -127,20 +127,38 @@
|
|||||||
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASLayout *)transitionLayoutWithAnimation:(BOOL)animated
|
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion
|
||||||
{
|
{
|
||||||
CGSize oldSize = self.calculatedSize;
|
CGSize oldSize = self.calculatedSize;
|
||||||
ASLayout *layout = [super transitionLayoutWithAnimation:animated];
|
[super transitionLayoutWithAnimation:animated
|
||||||
[self didRelayoutFromOldSize:oldSize toNewSize:layout.size];
|
shouldMeasureAsync:shouldMeasureAsync
|
||||||
return layout;
|
measurementCompletion:^{
|
||||||
|
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
||||||
|
if (completion) {
|
||||||
|
completion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASLayout *)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize animated:(BOOL)animated
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
|
animated:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion
|
||||||
{
|
{
|
||||||
CGSize oldSize = self.calculatedSize;
|
CGSize oldSize = self.calculatedSize;
|
||||||
ASLayout *layout = [super transitionLayoutWithSizeRange:constrainedSize animated:animated];
|
[super transitionLayoutWithSizeRange:constrainedSize
|
||||||
[self didRelayoutFromOldSize:oldSize toNewSize:layout.size];
|
animated:animated
|
||||||
return layout;
|
shouldMeasureAsync:shouldMeasureAsync
|
||||||
|
measurementCompletion:^{
|
||||||
|
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
||||||
|
if (completion) {
|
||||||
|
completion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didRelayoutFromOldSize:(CGSize)oldSize toNewSize:(CGSize)newSize
|
- (void)didRelayoutFromOldSize:(CGSize)oldSize toNewSize:(CGSize)newSize
|
||||||
|
@ -57,18 +57,38 @@ ASDISPLAYNODE_EXTERN_C_END
|
|||||||
- (void)didCompleteLayoutTransition:(id<ASContextTransitioning>)context;
|
- (void)didCompleteLayoutTransition:(id<ASContextTransitioning>)context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract Transitions the current layout with a new constrained size.
|
* @abstract Transitions the current layout with a new constrained size. Must be called on main thread.
|
||||||
*
|
*
|
||||||
* @discussion Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
* @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
||||||
* If the passed constrainedSize is the the same as the node's current constrained size, this method is noop.
|
*
|
||||||
|
* @param shouldMeasureAsync Measure the layout asynchronously.
|
||||||
|
*
|
||||||
|
* @param measurementCompletion Optional completion block called only if a new layout is calculated.
|
||||||
|
* It is called on main, right after the measurement and before -animateLayoutTransition:.
|
||||||
|
*
|
||||||
|
* @discussion If the passed constrainedSize is the the same as the node's current constrained size, this method is noop.
|
||||||
|
*
|
||||||
|
* @see animateLayoutTransition:
|
||||||
*/
|
*/
|
||||||
- (ASLayout *)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize animated:(BOOL)animated;
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
|
animated:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract Invalidates the current layout and begins a relayout of the node with the current `constrainedSize`.
|
* @abstract Invalidates the current layout and begins a relayout of the node with the current `constrainedSize`. Must be called on main thread.
|
||||||
*
|
*
|
||||||
* @discussion Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
* @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
||||||
|
*
|
||||||
|
* @param shouldMeasureAsync Measure the layout asynchronously.
|
||||||
|
*
|
||||||
|
* @param measurementCompletion Optional completion block called only if a new layout is calculated.
|
||||||
|
* It is called right after the measurement and before -animateLayoutTransition:.
|
||||||
|
*
|
||||||
|
* @see animateLayoutTransition:
|
||||||
*/
|
*/
|
||||||
- (ASLayout *)transitionLayoutWithAnimation:(BOOL)animated;
|
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
|
#import "ASDisplayNode+Beta.h"
|
||||||
#import "ASLayoutOptionsPrivate.h"
|
#import "ASLayoutOptionsPrivate.h"
|
||||||
|
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
@ -20,10 +21,10 @@
|
|||||||
#import "_ASDisplayView.h"
|
#import "_ASDisplayView.h"
|
||||||
#import "_ASScopeTimer.h"
|
#import "_ASScopeTimer.h"
|
||||||
#import "_ASCoreAnimationExtras.h"
|
#import "_ASCoreAnimationExtras.h"
|
||||||
|
#import "ASDisplayNodeLayoutContext.h"
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
#import "ASEqualityHelpers.h"
|
#import "ASEqualityHelpers.h"
|
||||||
#import "ASRunLoopQueue.h"
|
#import "ASRunLoopQueue.h"
|
||||||
#import "NSArray+Diffing.h"
|
|
||||||
|
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
@ -34,7 +35,7 @@ NSInteger const ASDefaultDrawingPriority = ASDefaultTransactionPriority;
|
|||||||
NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification = @"ASRenderingEngineDidDisplayScheduledNodes";
|
NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification = @"ASRenderingEngineDidDisplayScheduledNodes";
|
||||||
NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp";
|
NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp";
|
||||||
|
|
||||||
@interface ASDisplayNode () <UIGestureRecognizerDelegate, _ASDisplayLayerDelegate, _ASTransitionContextDelegate>
|
@interface ASDisplayNode () <UIGestureRecognizerDelegate, _ASDisplayLayerDelegate, _ASTransitionContextCompletionDelegate>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -350,9 +351,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
|
|
||||||
[self __setSupernode:nil];
|
[self __setSupernode:nil];
|
||||||
_pendingViewState = nil;
|
_pendingViewState = nil;
|
||||||
_replaceAsyncSentinel = nil;
|
|
||||||
|
|
||||||
_displaySentinel = nil;
|
_displaySentinel = nil;
|
||||||
|
_transitionSentinel = nil;
|
||||||
|
|
||||||
_pendingDisplayNodes = nil;
|
_pendingDisplayNodes = nil;
|
||||||
}
|
}
|
||||||
@ -583,111 +584,162 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
|
|
||||||
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
|
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
{
|
{
|
||||||
void (^manageSubnodesBlock)() = ^void() {
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
if (! [self shouldMeasureWithSizeRange:constrainedSize]) {
|
||||||
if (self.usesImplicitHierarchyManagement) {
|
return _layout;
|
||||||
[self __implicitlyInsertSubnodes];
|
}
|
||||||
[self __implicitlyRemoveSubnodes];
|
|
||||||
}
|
if ([self _hasTransitionsInProgress]) {
|
||||||
[self __completeLayoutCalculation];
|
// Invalidate transition sentinel to cancel transitions in progress
|
||||||
};
|
[self _invalidateTransitionSentinel];
|
||||||
|
// Tell subnodes to exit layout pending state and clear related properties
|
||||||
|
ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) {
|
||||||
|
node.hierarchyState &= (~ASHierarchyStateLayoutPending);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ASLayout *previousLayout = _layout;
|
||||||
|
ASSizeRange previousConstrainedSize = _constrainedSize;
|
||||||
|
ASLayout *newLayout = [self calculateLayoutThatFits:constrainedSize];
|
||||||
|
|
||||||
return [self measureWithSizeRange:constrainedSize completion:^{
|
if (ASHierarchyStateIncludesLayoutPending(_hierarchyState)) {
|
||||||
if (!self.isNodeLoaded) {
|
_pendingLayoutContext = [[ASDisplayNodeLayoutContext alloc] initWithNode:self
|
||||||
manageSubnodesBlock();
|
pendingLayout:newLayout
|
||||||
} else {
|
pendingConstrainedSize:constrainedSize
|
||||||
ASPerformBlockOnMainThread(manageSubnodesBlock);
|
previousLayout:previousLayout
|
||||||
|
previousConstrainedSize:previousConstrainedSize];
|
||||||
|
} else {
|
||||||
|
ASDisplayNodeLayoutContext *layoutContext;
|
||||||
|
if (self.usesImplicitHierarchyManagement) {
|
||||||
|
layoutContext = [[ASDisplayNodeLayoutContext alloc] initWithNode:self
|
||||||
|
pendingLayout:newLayout
|
||||||
|
pendingConstrainedSize:constrainedSize
|
||||||
|
previousLayout:previousLayout
|
||||||
|
previousConstrainedSize:previousConstrainedSize];
|
||||||
}
|
}
|
||||||
}];
|
[self applyLayout:newLayout constrainedSize:constrainedSize layoutContext:layoutContext];
|
||||||
|
[self _completeLayoutCalculation];
|
||||||
|
}
|
||||||
|
|
||||||
|
return newLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize completion:(void(^)())completion
|
- (BOOL)shouldMeasureWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
if (![self __shouldSize])
|
if (![self __shouldSize]) {
|
||||||
return nil;
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ASHierarchyStateIncludesLayoutPending(_hierarchyState) && constrainedSize.transitionID != _pendingTransitionID) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
// only calculate the size if
|
// only calculate the size if
|
||||||
// - we haven't already
|
// - we haven't already
|
||||||
// - the constrained size range is different
|
// - the constrained size range is different
|
||||||
if (!_flags.isMeasured || !ASSizeRangeEqualToSizeRange(constrainedSize, _constrainedSize)) {
|
return (!_flags.isMeasured || !ASSizeRangeEqualToSizeRange(constrainedSize, _constrainedSize));
|
||||||
_previousLayout = _layout;
|
}
|
||||||
_layout = [self calculateLayoutThatFits:constrainedSize];
|
|
||||||
|
|
||||||
ASDisplayNodeAssertTrue(_layout.layoutableObject == self);
|
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
||||||
ASDisplayNodeAssertTrue(_layout.size.width >= 0.0);
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
ASDisplayNodeAssertTrue(_layout.size.height >= 0.0);
|
measurementCompletion:(void(^)())completion
|
||||||
|
{
|
||||||
_previousConstrainedSize = _constrainedSize;
|
ASSizeRange currentConstrainedSize = _constrainedSize;
|
||||||
_constrainedSize = constrainedSize;
|
[self invalidateCalculatedLayout];
|
||||||
|
[self transitionLayoutWithSizeRange:currentConstrainedSize
|
||||||
if (self.usesImplicitHierarchyManagement) {
|
animated:animated
|
||||||
[self __calculateSubnodeOperations];
|
shouldMeasureAsync:shouldMeasureAsync
|
||||||
}
|
measurementCompletion:completion];
|
||||||
_flags.isMeasured = YES;
|
}
|
||||||
|
|
||||||
completion();
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
|
animated:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssertMainThread();
|
||||||
|
if (! [self shouldMeasureWithSizeRange:constrainedSize]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
ASDisplayNodeAssert(ASHierarchyStateIncludesLayoutPending(_hierarchyState) == NO, @"Can't start a transition when one of the supernodes is performing one.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return _layout;
|
int32_t transitionID = [self _newTransitionID];
|
||||||
}
|
constrainedSize.transitionID = transitionID;
|
||||||
|
|
||||||
- (ASLayout *)transitionLayoutWithAnimation:(BOOL)animated
|
ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) {
|
||||||
{
|
ASDisplayNodeAssert([node _hasTransitionsInProgress] == NO, @"Can't start a transition when one of the subnodes is performing one.");
|
||||||
[self invalidateCalculatedLayout];
|
node.hierarchyState |= ASHierarchyStateLayoutPending;
|
||||||
return [self transitionLayoutWithSizeRange:_constrainedSize animated:animated];
|
node.pendingTransitionID = transitionID;
|
||||||
}
|
});
|
||||||
|
|
||||||
- (ASLayout *)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize animated:(BOOL)animated
|
|
||||||
{
|
|
||||||
BOOL disableImplicitHierarchyManagement = self.usesImplicitHierarchyManagement == NO;
|
|
||||||
self.usesImplicitHierarchyManagement = YES; // Temporary flag for 1.9.x
|
|
||||||
|
|
||||||
return [self measureWithSizeRange:constrainedSize completion:^{
|
void (^transitionBlock)() = ^{
|
||||||
if (disableImplicitHierarchyManagement) {
|
ASLayout *newLayout;
|
||||||
self.usesImplicitHierarchyManagement = NO; // Temporary flag for 1.9.x
|
{
|
||||||
}
|
|
||||||
|
|
||||||
ASPerformBlockOnMainThread(^{
|
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
_transitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated delegate:self];
|
BOOL disableImplicitHierarchyManagement = self.usesImplicitHierarchyManagement == NO;
|
||||||
[self __implicitlyInsertSubnodes];
|
self.usesImplicitHierarchyManagement = YES; // Temporary flag for 1.9.x
|
||||||
|
newLayout = [self calculateLayoutThatFits:constrainedSize];
|
||||||
|
if (disableImplicitHierarchyManagement) {
|
||||||
|
self.usesImplicitHierarchyManagement = NO; // Temporary flag for 1.9.x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([self _shouldAbortTransitionWithID:transitionID]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASPerformBlockOnMainThread(^{
|
||||||
|
if ([self _shouldAbortTransitionWithID:transitionID]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
|
||||||
|
ASLayout *previousLayout = _layout;
|
||||||
|
ASSizeRange previousConstrainedSize = _constrainedSize;
|
||||||
|
[self applyLayout:newLayout constrainedSize:constrainedSize layoutContext:nil];
|
||||||
|
|
||||||
|
[self _invalidateTransitionSentinel];
|
||||||
|
|
||||||
|
ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) {
|
||||||
|
[node applyPendingLayoutContext];
|
||||||
|
[node _completeLayoutCalculation];
|
||||||
|
node.hierarchyState &= (~ASHierarchyStateLayoutPending);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (completion) {
|
||||||
|
completion();
|
||||||
|
}
|
||||||
|
|
||||||
|
_pendingLayoutContext = [[ASDisplayNodeLayoutContext alloc] initWithNode:self
|
||||||
|
pendingLayout:newLayout
|
||||||
|
pendingConstrainedSize:constrainedSize
|
||||||
|
previousLayout:previousLayout
|
||||||
|
previousConstrainedSize:previousConstrainedSize];
|
||||||
|
[_pendingLayoutContext applySubnodeInsertions];
|
||||||
|
|
||||||
|
_transitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated
|
||||||
|
layoutDelegate:_pendingLayoutContext
|
||||||
|
completionDelegate:self];
|
||||||
[self animateLayoutTransition:_transitionContext];
|
[self animateLayoutTransition:_transitionContext];
|
||||||
});
|
});
|
||||||
}];
|
};
|
||||||
}
|
|
||||||
|
|
||||||
- (void)__calculateSubnodeOperations
|
if (shouldMeasureAsync) {
|
||||||
{
|
ASPerformBlockOnBackgroundThread(transitionBlock);
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
|
||||||
if (_previousLayout) {
|
|
||||||
NSIndexSet *insertions, *deletions;
|
|
||||||
[_previousLayout.immediateSublayouts asdk_diffWithArray:_layout.immediateSublayouts
|
|
||||||
insertions:&insertions
|
|
||||||
deletions:&deletions
|
|
||||||
compareBlock:^BOOL(ASLayout *lhs, ASLayout *rhs) {
|
|
||||||
return ASObjectIsEqual(lhs.layoutableObject, rhs.layoutableObject);
|
|
||||||
}];
|
|
||||||
filterNodesInLayoutAtIndexes(_layout, insertions, &_insertedSubnodes, &_insertedSubnodePositions);
|
|
||||||
filterNodesInLayoutAtIndexesWithIntersectingNodes(_previousLayout,
|
|
||||||
deletions,
|
|
||||||
_insertedSubnodes,
|
|
||||||
&_removedSubnodes,
|
|
||||||
&_removedSubnodePositions);
|
|
||||||
} else {
|
} else {
|
||||||
NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_layout.immediateSublayouts count])];
|
transitionBlock();
|
||||||
filterNodesInLayoutAtIndexes(_layout, indexes, &_insertedSubnodes, &_insertedSubnodePositions);
|
|
||||||
_removedSubnodes = nil;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)__completeLayoutCalculation
|
- (void)_completeLayoutCalculation
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
_insertedSubnodes = nil;
|
|
||||||
_removedSubnodes = nil;
|
|
||||||
_previousLayout = nil;
|
|
||||||
|
|
||||||
[self calculatedLayoutDidChange];
|
[self calculatedLayoutDidChange];
|
||||||
|
|
||||||
// we generate placeholders at measureWithSizeRange: time so that a node is guaranteed
|
// we generate placeholders at measureWithSizeRange: time so that a node is guaranteed
|
||||||
@ -704,53 +756,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract Stores the nodes at the given indexes in the `storedNodes` array, storing indexes in a `storedPositions` c++ vector.
|
|
||||||
*/
|
|
||||||
static inline void filterNodesInLayoutAtIndexes(
|
|
||||||
ASLayout *layout,
|
|
||||||
NSIndexSet *indexes,
|
|
||||||
NSArray<ASDisplayNode *> * __strong *storedNodes,
|
|
||||||
std::vector<NSInteger> *storedPositions
|
|
||||||
)
|
|
||||||
{
|
|
||||||
filterNodesInLayoutAtIndexesWithIntersectingNodes(layout, indexes, nil, storedNodes, storedPositions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract Stores the nodes at the given indexes in the `storedNodes` array, storing indexes in a `storedPositions` c++ vector.
|
|
||||||
* @discussion If the node exists in the `intersectingNodes` array, the node is not added to `storedNodes`.
|
|
||||||
*/
|
|
||||||
static inline void filterNodesInLayoutAtIndexesWithIntersectingNodes(
|
|
||||||
ASLayout *layout,
|
|
||||||
NSIndexSet *indexes,
|
|
||||||
NSArray<ASDisplayNode *> *intersectingNodes,
|
|
||||||
NSArray<ASDisplayNode *> * __strong *storedNodes,
|
|
||||||
std::vector<NSInteger> *storedPositions
|
|
||||||
)
|
|
||||||
{
|
|
||||||
NSMutableArray<ASDisplayNode *> *nodes = [NSMutableArray array];
|
|
||||||
std::vector<NSInteger> positions = std::vector<NSInteger>();
|
|
||||||
NSInteger idx = [indexes firstIndex];
|
|
||||||
while (idx != NSNotFound) {
|
|
||||||
BOOL skip = NO;
|
|
||||||
ASDisplayNode *node = (ASDisplayNode *)layout.immediateSublayouts[idx].layoutableObject;
|
|
||||||
ASDisplayNodeCAssert(node, @"A flattened layout must consist exclusively of node sublayouts");
|
|
||||||
for (ASDisplayNode *i in intersectingNodes) {
|
|
||||||
if (node == i) {
|
|
||||||
skip = YES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!skip) {
|
|
||||||
[nodes addObject:node];
|
|
||||||
positions.push_back(idx);
|
|
||||||
}
|
|
||||||
idx = [indexes indexGreaterThanIndex:idx];
|
|
||||||
}
|
|
||||||
*storedNodes = nodes;
|
|
||||||
*storedPositions = positions;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)calculatedLayoutDidChange
|
- (void)calculatedLayoutDidChange
|
||||||
{
|
{
|
||||||
@ -779,66 +784,12 @@ static inline void filterNodesInLayoutAtIndexesWithIntersectingNodes(
|
|||||||
|
|
||||||
- (void)didCompleteLayoutTransition:(id<ASContextTransitioning>)context
|
- (void)didCompleteLayoutTransition:(id<ASContextTransitioning>)context
|
||||||
{
|
{
|
||||||
[self __implicitlyRemoveSubnodes];
|
[_pendingLayoutContext applySubnodeRemovals];
|
||||||
[self __completeLayoutCalculation];
|
[self _completeLayoutCalculation];
|
||||||
|
_pendingLayoutContext = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Implicit node hierarchy managagment
|
#pragma mark - _ASTransitionContextCompletionDelegate
|
||||||
|
|
||||||
- (void)__implicitlyInsertSubnodes
|
|
||||||
{
|
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
|
||||||
for (NSInteger i = 0; i < [_insertedSubnodes count]; i++) {
|
|
||||||
NSInteger p = _insertedSubnodePositions[i];
|
|
||||||
[self insertSubnode:_insertedSubnodes[i] atIndex:p];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)__implicitlyRemoveSubnodes
|
|
||||||
{
|
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
|
||||||
for (NSInteger i = 0; i < [_removedSubnodes count]; i++) {
|
|
||||||
[_removedSubnodes[i] removeFromSupernode];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - _ASTransitionContextDelegate
|
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
|
||||||
{
|
|
||||||
return _subnodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
|
||||||
{
|
|
||||||
return _insertedSubnodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
|
||||||
{
|
|
||||||
return _removedSubnodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key
|
|
||||||
{
|
|
||||||
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
|
||||||
return _previousLayout;
|
|
||||||
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
|
||||||
return _layout;
|
|
||||||
} else {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key
|
|
||||||
{
|
|
||||||
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
|
||||||
return _previousConstrainedSize;
|
|
||||||
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
|
||||||
return _constrainedSize;
|
|
||||||
} else {
|
|
||||||
return ASSizeRangeMake(CGSizeZero, CGSizeZero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete
|
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete
|
||||||
{
|
{
|
||||||
@ -1896,6 +1847,13 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
return _constrainedSize;
|
return _constrainedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setPendingTransitionID:(int32_t)pendingTransitionID
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
ASDisplayNodeAssertTrue(_pendingTransitionID < pendingTransitionID);
|
||||||
|
_pendingTransitionID = pendingTransitionID;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setPreferredFrameSize:(CGSize)preferredFrameSize
|
- (void)setPreferredFrameSize:(CGSize)preferredFrameSize
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
@ -2211,6 +2169,19 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((newState & ASHierarchyStateLayoutPending) != (oldState & ASHierarchyStateLayoutPending)) {
|
||||||
|
if (newState & ASHierarchyStateLayoutPending) {
|
||||||
|
// Entering layout pending state
|
||||||
|
} else {
|
||||||
|
// Leaving layout pending state, reset related properties
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
_pendingTransitionID = 0;
|
||||||
|
_pendingLayoutContext = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (newState != oldState) {
|
if (newState != oldState) {
|
||||||
LOG(@"setHierarchyState: oldState = %lu, newState = %lu", (unsigned long)oldState, (unsigned long)newState);
|
LOG(@"setHierarchyState: oldState = %lu, newState = %lu", (unsigned long)oldState, (unsigned long)newState);
|
||||||
}
|
}
|
||||||
@ -2236,6 +2207,37 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)applyPendingLayoutContext
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
if (_pendingLayoutContext) {
|
||||||
|
[self applyLayout:_pendingLayoutContext.pendingLayout
|
||||||
|
constrainedSize:_pendingLayoutContext.pendingConstrainedSize
|
||||||
|
layoutContext:_pendingLayoutContext];
|
||||||
|
_pendingLayoutContext = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applyLayout:(ASLayout *)layout
|
||||||
|
constrainedSize:(ASSizeRange)constrainedSize
|
||||||
|
layoutContext:(ASDisplayNodeLayoutContext *)layoutContext
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
_layout = layout;
|
||||||
|
|
||||||
|
ASDisplayNodeAssertTrue(layout.layoutableObject == self);
|
||||||
|
ASDisplayNodeAssertTrue(layout.size.width >= 0.0);
|
||||||
|
ASDisplayNodeAssertTrue(layout.size.height >= 0.0);
|
||||||
|
|
||||||
|
_constrainedSize = constrainedSize;
|
||||||
|
_flags.isMeasured = YES;
|
||||||
|
|
||||||
|
if (self.usesImplicitHierarchyManagement && layoutContext != nil) {
|
||||||
|
[layoutContext applySubnodeInsertions];
|
||||||
|
[layoutContext applySubnodeRemovals];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)layout
|
- (void)layout
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
@ -2552,24 +2554,31 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority";
|
|||||||
return asyncSizingQueue;
|
return asyncSizingQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_isMarkedForReplacement
|
- (BOOL)_hasTransitionsInProgress
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
return _transitionSentinel != nil;
|
||||||
return _replaceAsyncSentinel != nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This method doesn't appear to be called, and could be removed.
|
- (void)_invalidateTransitionSentinel
|
||||||
// However, it may be useful for an API similar to what Paper used to create a new node hierarchy,
|
|
||||||
// trigger asynchronous measurement and display on it, and have it swap out and replace an old hierarchy.
|
|
||||||
- (ASSentinel *)_asyncReplaceSentinel
|
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
_transitionSentinel = nil;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_replaceAsyncSentinel) {
|
- (BOOL)_shouldAbortTransitionWithID:(int32_t)transitionID
|
||||||
_replaceAsyncSentinel = [[ASSentinel alloc] init];
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
return _transitionSentinel == nil || transitionID != _transitionSentinel.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int32_t)_newTransitionID
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
if (!_transitionSentinel) {
|
||||||
|
_transitionSentinel = [[ASSentinel alloc] init];
|
||||||
}
|
}
|
||||||
return _replaceAsyncSentinel;
|
return [_transitionSentinel increment];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calls completion with nil to indicated cancellation
|
// Calls completion with nil to indicated cancellation
|
||||||
|
@ -30,6 +30,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
CGSize min;
|
CGSize min;
|
||||||
CGSize max;
|
CGSize max;
|
||||||
|
int32_t transitionID;
|
||||||
} ASSizeRange;
|
} ASSizeRange;
|
||||||
|
|
||||||
extern ASRelativeDimension const ASRelativeDimensionUnconstrained;
|
extern ASRelativeDimension const ASRelativeDimensionUnconstrained;
|
||||||
|
@ -331,7 +331,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
|
|||||||
// FIXME: what about the degenerate case where we are calling setNeedsDisplay faster than the jobs are dequeuing
|
// FIXME: what about the degenerate case where we are calling setNeedsDisplay faster than the jobs are dequeuing
|
||||||
// from the displayQueue? Need to not cancel early fails from displaySentinel changes.
|
// from the displayQueue? Need to not cancel early fails from displaySentinel changes.
|
||||||
ASSentinel *displaySentinel = (asynchronously ? _displaySentinel : nil);
|
ASSentinel *displaySentinel = (asynchronously ? _displaySentinel : nil);
|
||||||
int64_t displaySentinelValue = [displaySentinel increment];
|
int32_t displaySentinelValue = [displaySentinel increment];
|
||||||
|
|
||||||
asdisplaynode_iscancelled_block_t isCancelledBlock = ^{
|
asdisplaynode_iscancelled_block_t isCancelledBlock = ^{
|
||||||
return BOOL(displaySentinelValue != displaySentinel.value);
|
return BOOL(displaySentinelValue != displaySentinel.value);
|
||||||
|
@ -45,9 +45,17 @@ typedef NS_OPTIONS(NSUInteger, ASHierarchyState)
|
|||||||
ASHierarchyStateRangeManaged = 1 << 1,
|
ASHierarchyStateRangeManaged = 1 << 1,
|
||||||
/** Down-propogated version of _flags.visibilityNotificationsDisabled. This flag is very rarely set, but by having it
|
/** Down-propogated version of _flags.visibilityNotificationsDisabled. This flag is very rarely set, but by having it
|
||||||
locally available to nodes, they do not have to walk up supernodes at the critical points it is checked. */
|
locally available to nodes, they do not have to walk up supernodes at the critical points it is checked. */
|
||||||
ASHierarchyStateTransitioningSupernodes = 1 << 2
|
ASHierarchyStateTransitioningSupernodes = 1 << 2,
|
||||||
|
/** One of the supernodes of this node is performing a transition.
|
||||||
|
Any layout calculated during this state should not be applied immediately, but pending until later. */
|
||||||
|
ASHierarchyStateLayoutPending = 1 << 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline BOOL ASHierarchyStateIncludesLayoutPending(ASHierarchyState hierarchyState)
|
||||||
|
{
|
||||||
|
return ((hierarchyState & ASHierarchyStateLayoutPending) == ASHierarchyStateLayoutPending);
|
||||||
|
}
|
||||||
|
|
||||||
@interface ASDisplayNode ()
|
@interface ASDisplayNode ()
|
||||||
{
|
{
|
||||||
@protected
|
@protected
|
||||||
|
@ -18,12 +18,14 @@
|
|||||||
#import "ASThread.h"
|
#import "ASThread.h"
|
||||||
#import "ASLayoutOptions.h"
|
#import "ASLayoutOptions.h"
|
||||||
#import "_ASTransitionContext.h"
|
#import "_ASTransitionContext.h"
|
||||||
|
#import "ASDisplayNodeLayoutContext.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@protocol _ASDisplayLayerDelegate;
|
@protocol _ASDisplayLayerDelegate;
|
||||||
@class _ASDisplayLayer;
|
@class _ASDisplayLayer;
|
||||||
@class _ASPendingState;
|
@class _ASPendingState;
|
||||||
|
@class ASSentinel;
|
||||||
|
|
||||||
BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector);
|
BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector);
|
||||||
|
|
||||||
@ -89,15 +91,13 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
|
|||||||
ASDisplayNode * __weak _supernode;
|
ASDisplayNode * __weak _supernode;
|
||||||
|
|
||||||
ASSentinel *_displaySentinel;
|
ASSentinel *_displaySentinel;
|
||||||
ASSentinel *_replaceAsyncSentinel;
|
ASSentinel *_transitionSentinel;
|
||||||
|
|
||||||
// This is the desired contentsScale, not the scale at which the layer's contents should be displayed
|
// This is the desired contentsScale, not the scale at which the layer's contents should be displayed
|
||||||
CGFloat _contentsScaleForDisplay;
|
CGFloat _contentsScaleForDisplay;
|
||||||
|
|
||||||
ASLayout *_previousLayout;
|
|
||||||
ASLayout *_layout;
|
ASLayout *_layout;
|
||||||
|
|
||||||
ASSizeRange _previousConstrainedSize;
|
|
||||||
ASSizeRange _constrainedSize;
|
ASSizeRange _constrainedSize;
|
||||||
|
|
||||||
UIEdgeInsets _hitTestSlop;
|
UIEdgeInsets _hitTestSlop;
|
||||||
@ -107,11 +107,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
|
|||||||
_ASTransitionContext *_transitionContext;
|
_ASTransitionContext *_transitionContext;
|
||||||
BOOL _usesImplicitHierarchyManagement;
|
BOOL _usesImplicitHierarchyManagement;
|
||||||
|
|
||||||
NSArray<ASDisplayNode *> *_insertedSubnodes;
|
int32_t _pendingTransitionID;
|
||||||
NSArray<ASDisplayNode *> *_removedSubnodes;
|
ASDisplayNodeLayoutContext *_pendingLayoutContext;
|
||||||
std::vector<NSInteger> _insertedSubnodePositions;
|
|
||||||
std::vector<NSInteger> _removedSubnodePositions;
|
|
||||||
|
|
||||||
ASDisplayNodeViewBlock _viewBlock;
|
ASDisplayNodeViewBlock _viewBlock;
|
||||||
ASDisplayNodeLayerBlock _layerBlock;
|
ASDisplayNodeLayerBlock _layerBlock;
|
||||||
ASDisplayNodeDidLoadBlock _nodeLoadedBlock;
|
ASDisplayNodeDidLoadBlock _nodeLoadedBlock;
|
||||||
|
33
AsyncDisplayKit/Private/ASDisplayNodeLayoutContext.h
Normal file
33
AsyncDisplayKit/Private/ASDisplayNodeLayoutContext.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// ASDisplayNodeLayoutContext.h
|
||||||
|
// AsyncDisplayKit
|
||||||
|
//
|
||||||
|
// Created by Huy Nguyen on 3/8/16.
|
||||||
|
// Copyright © 2016 Facebook. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "ASDimension.h"
|
||||||
|
#import "_ASTransitionContext.h"
|
||||||
|
|
||||||
|
@class ASDisplayNode;
|
||||||
|
@class ASLayout;
|
||||||
|
|
||||||
|
@interface ASDisplayNodeLayoutContext : NSObject <_ASTransitionContextLayoutDelegate>
|
||||||
|
|
||||||
|
@property (nonatomic, readonly, weak) ASDisplayNode *node;
|
||||||
|
@property (nonatomic, readonly, strong) ASLayout *pendingLayout;
|
||||||
|
@property (nonatomic, readonly, assign) ASSizeRange pendingConstrainedSize;
|
||||||
|
@property (nonatomic, readonly, strong) ASLayout *previousLayout;
|
||||||
|
@property (nonatomic, readonly, assign) ASSizeRange previousConstrainedSize;
|
||||||
|
|
||||||
|
- (instancetype)initWithNode:(ASDisplayNode *)node
|
||||||
|
pendingLayout:(ASLayout *)pendingLayout
|
||||||
|
pendingConstrainedSize:(ASSizeRange)pendingConstrainedSize
|
||||||
|
previousLayout:(ASLayout *)previousLayout
|
||||||
|
previousConstrainedSize:(ASSizeRange)previousConstrainedSize;
|
||||||
|
|
||||||
|
- (void)applySubnodeInsertions;
|
||||||
|
|
||||||
|
- (void)applySubnodeRemovals;
|
||||||
|
|
||||||
|
@end
|
190
AsyncDisplayKit/Private/ASDisplayNodeLayoutContext.mm
Normal file
190
AsyncDisplayKit/Private/ASDisplayNodeLayoutContext.mm
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
//
|
||||||
|
// ASDisplayNodeLayoutContext.mm
|
||||||
|
// AsyncDisplayKit
|
||||||
|
//
|
||||||
|
// Created by Huy Nguyen on 3/8/16.
|
||||||
|
// Copyright © 2016 Facebook. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "ASDisplayNodeLayoutContext.h"
|
||||||
|
|
||||||
|
#import "ASDisplayNode.h"
|
||||||
|
#import "ASDisplayNodeInternal.h"
|
||||||
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
|
#import "ASLayout.h"
|
||||||
|
|
||||||
|
#import <vector>
|
||||||
|
|
||||||
|
#import "NSArray+Diffing.h"
|
||||||
|
#import "ASEqualityHelpers.h"
|
||||||
|
|
||||||
|
@implementation ASDisplayNodeLayoutContext {
|
||||||
|
ASDN::RecursiveMutex _propertyLock;
|
||||||
|
BOOL _calculatedSubnodeOperations;
|
||||||
|
NSArray<ASDisplayNode *> *_insertedSubnodes;
|
||||||
|
NSArray<ASDisplayNode *> *_removedSubnodes;
|
||||||
|
std::vector<NSInteger> _insertedSubnodePositions;
|
||||||
|
std::vector<NSInteger> _removedSubnodePositions;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithNode:(ASDisplayNode *)node
|
||||||
|
pendingLayout:(ASLayout *)pendingLayout
|
||||||
|
pendingConstrainedSize:(ASSizeRange)pendingConstrainedSize
|
||||||
|
previousLayout:(ASLayout *)previousLayout
|
||||||
|
previousConstrainedSize:(ASSizeRange)previousConstrainedSize
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_node = node;
|
||||||
|
_pendingLayout = pendingLayout;
|
||||||
|
_pendingConstrainedSize = pendingConstrainedSize;
|
||||||
|
_previousLayout = previousLayout;
|
||||||
|
_previousConstrainedSize = previousConstrainedSize;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applySubnodeInsertions
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
|
for (NSInteger i = 0; i < [_insertedSubnodes count]; i++) {
|
||||||
|
NSInteger p = _insertedSubnodePositions[i];
|
||||||
|
[_node insertSubnode:_insertedSubnodes[i] atIndex:p];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applySubnodeRemovals
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
|
for (NSInteger i = 0; i < [_removedSubnodes count]; i++) {
|
||||||
|
[_removedSubnodes[i] removeFromSupernode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)calculateSubnodeOperationsIfNeeded
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
if (_calculatedSubnodeOperations) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_previousLayout) {
|
||||||
|
NSIndexSet *insertions, *deletions;
|
||||||
|
[_previousLayout.immediateSublayouts asdk_diffWithArray:_pendingLayout.immediateSublayouts
|
||||||
|
insertions:&insertions
|
||||||
|
deletions:&deletions
|
||||||
|
compareBlock:^BOOL(ASLayout *lhs, ASLayout *rhs) {
|
||||||
|
return ASObjectIsEqual(lhs.layoutableObject, rhs.layoutableObject);
|
||||||
|
}];
|
||||||
|
filterNodesInLayoutAtIndexes(_pendingLayout, insertions, &_insertedSubnodes, &_insertedSubnodePositions);
|
||||||
|
filterNodesInLayoutAtIndexesWithIntersectingNodes(_previousLayout,
|
||||||
|
deletions,
|
||||||
|
_insertedSubnodes,
|
||||||
|
&_removedSubnodes,
|
||||||
|
&_removedSubnodePositions);
|
||||||
|
} else {
|
||||||
|
NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_pendingLayout.immediateSublayouts count])];
|
||||||
|
filterNodesInLayoutAtIndexes(_pendingLayout, indexes, &_insertedSubnodes, &_insertedSubnodePositions);
|
||||||
|
_removedSubnodes = nil;
|
||||||
|
}
|
||||||
|
_calculatedSubnodeOperations = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - _ASTransitionContextDelegate
|
||||||
|
|
||||||
|
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
return _node.subnodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
|
return _insertedSubnodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
|
return _removedSubnodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
||||||
|
return _previousLayout;
|
||||||
|
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
||||||
|
return _pendingLayout;
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
||||||
|
return _previousConstrainedSize;
|
||||||
|
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
||||||
|
return _pendingConstrainedSize;
|
||||||
|
} else {
|
||||||
|
return ASSizeRangeMake(CGSizeZero, CGSizeZero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Filter helpers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Stores the nodes at the given indexes in the `storedNodes` array, storing indexes in a `storedPositions` c++ vector.
|
||||||
|
*/
|
||||||
|
static inline void filterNodesInLayoutAtIndexes(
|
||||||
|
ASLayout *layout,
|
||||||
|
NSIndexSet *indexes,
|
||||||
|
NSArray<ASDisplayNode *> * __strong *storedNodes,
|
||||||
|
std::vector<NSInteger> *storedPositions
|
||||||
|
)
|
||||||
|
{
|
||||||
|
filterNodesInLayoutAtIndexesWithIntersectingNodes(layout, indexes, nil, storedNodes, storedPositions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Stores the nodes at the given indexes in the `storedNodes` array, storing indexes in a `storedPositions` c++ vector.
|
||||||
|
* @discussion If the node exists in the `intersectingNodes` array, the node is not added to `storedNodes`.
|
||||||
|
*/
|
||||||
|
static inline void filterNodesInLayoutAtIndexesWithIntersectingNodes(
|
||||||
|
ASLayout *layout,
|
||||||
|
NSIndexSet *indexes,
|
||||||
|
NSArray<ASDisplayNode *> *intersectingNodes,
|
||||||
|
NSArray<ASDisplayNode *> * __strong *storedNodes,
|
||||||
|
std::vector<NSInteger> *storedPositions
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NSMutableArray<ASDisplayNode *> *nodes = [NSMutableArray array];
|
||||||
|
std::vector<NSInteger> positions = std::vector<NSInteger>();
|
||||||
|
NSInteger idx = [indexes firstIndex];
|
||||||
|
while (idx != NSNotFound) {
|
||||||
|
BOOL skip = NO;
|
||||||
|
ASDisplayNode *node = (ASDisplayNode *)layout.immediateSublayouts[idx].layoutableObject;
|
||||||
|
ASDisplayNodeCAssert(node, @"A flattened layout must consist exclusively of node sublayouts");
|
||||||
|
for (ASDisplayNode *i in intersectingNodes) {
|
||||||
|
if (node == i) {
|
||||||
|
skip = YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skip) {
|
||||||
|
[nodes addObject:node];
|
||||||
|
positions.push_back(idx);
|
||||||
|
}
|
||||||
|
idx = [indexes indexGreaterThanIndex:idx];
|
||||||
|
}
|
||||||
|
*storedNodes = nodes;
|
||||||
|
*storedPositions = positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -13,7 +13,7 @@
|
|||||||
@class ASLayout;
|
@class ASLayout;
|
||||||
@class _ASTransitionContext;
|
@class _ASTransitionContext;
|
||||||
|
|
||||||
@protocol _ASTransitionContextDelegate <NSObject>
|
@protocol _ASTransitionContextLayoutDelegate <NSObject>
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context;
|
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context;
|
||||||
|
|
||||||
@ -23,6 +23,10 @@
|
|||||||
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key;
|
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key;
|
||||||
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key;
|
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol _ASTransitionContextCompletionDelegate <NSObject>
|
||||||
|
|
||||||
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete;
|
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -31,6 +35,8 @@
|
|||||||
|
|
||||||
@property (assign, readonly, nonatomic, getter=isAnimated) BOOL animated;
|
@property (assign, readonly, nonatomic, getter=isAnimated) BOOL animated;
|
||||||
|
|
||||||
- (instancetype)initWithAnimation:(BOOL)animated delegate:(id<_ASTransitionContextDelegate>)delegate;
|
- (instancetype)initWithAnimation:(BOOL)animated
|
||||||
|
layoutDelegate:(id<_ASTransitionContextLayoutDelegate>)layoutDelegate
|
||||||
|
completionDelegate:(id<_ASTransitionContextCompletionDelegate>)completionDelegate;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -16,18 +16,22 @@ NSString * const ASTransitionContextToLayoutKey = @"org.asyncdisplaykit.ASTransi
|
|||||||
|
|
||||||
@interface _ASTransitionContext ()
|
@interface _ASTransitionContext ()
|
||||||
|
|
||||||
@property (weak, nonatomic) id<_ASTransitionContextDelegate> delegate;
|
@property (weak, nonatomic) id<_ASTransitionContextLayoutDelegate> layoutDelegate;
|
||||||
|
@property (weak, nonatomic) id<_ASTransitionContextCompletionDelegate> completionDelegate;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _ASTransitionContext
|
@implementation _ASTransitionContext
|
||||||
|
|
||||||
- (instancetype)initWithAnimation:(BOOL)animated delegate:(id<_ASTransitionContextDelegate>)delegate
|
- (instancetype)initWithAnimation:(BOOL)animated
|
||||||
|
layoutDelegate:(id<_ASTransitionContextLayoutDelegate>)layoutDelegate
|
||||||
|
completionDelegate:(id<_ASTransitionContextCompletionDelegate>)completionDelegate
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_animated = animated;
|
_animated = animated;
|
||||||
_delegate = delegate;
|
_layoutDelegate = layoutDelegate;
|
||||||
|
_completionDelegate = completionDelegate;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -36,17 +40,17 @@ NSString * const ASTransitionContextToLayoutKey = @"org.asyncdisplaykit.ASTransi
|
|||||||
|
|
||||||
- (ASLayout *)layoutForKey:(NSString *)key
|
- (ASLayout *)layoutForKey:(NSString *)key
|
||||||
{
|
{
|
||||||
return [_delegate transitionContext:self layoutForKey:key];
|
return [_layoutDelegate transitionContext:self layoutForKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASSizeRange)constrainedSizeForKey:(NSString *)key
|
- (ASSizeRange)constrainedSizeForKey:(NSString *)key
|
||||||
{
|
{
|
||||||
return [_delegate transitionContext:self constrainedSizeForKey:key];
|
return [_layoutDelegate transitionContext:self constrainedSizeForKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)initialFrameForNode:(ASDisplayNode *)node
|
- (CGRect)initialFrameForNode:(ASDisplayNode *)node
|
||||||
{
|
{
|
||||||
for (ASDisplayNode *subnode in [_delegate currentSubnodesWithTransitionContext:self]) {
|
for (ASDisplayNode *subnode in [_layoutDelegate currentSubnodesWithTransitionContext:self]) {
|
||||||
if (node == subnode) {
|
if (node == subnode) {
|
||||||
return node.frame;
|
return node.frame;
|
||||||
}
|
}
|
||||||
@ -75,17 +79,17 @@ NSString * const ASTransitionContextToLayoutKey = @"org.asyncdisplaykit.ASTransi
|
|||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)insertedSubnodes
|
- (NSArray<ASDisplayNode *> *)insertedSubnodes
|
||||||
{
|
{
|
||||||
return [_delegate insertedSubnodesWithTransitionContext:self];
|
return [_layoutDelegate insertedSubnodesWithTransitionContext:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)removedSubnodes
|
- (NSArray<ASDisplayNode *> *)removedSubnodes
|
||||||
{
|
{
|
||||||
return [_delegate removedSubnodesWithTransitionContext:self];
|
return [_layoutDelegate removedSubnodesWithTransitionContext:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)completeTransition:(BOOL)didComplete
|
- (void)completeTransition:(BOOL)didComplete
|
||||||
{
|
{
|
||||||
[_delegate transitionContext:self didComplete:didComplete];
|
[_completionDelegate transitionContext:self didComplete:didComplete];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user