Allow layouts to be accessible in context

This commit is contained in:
Levi McCallum 2016-02-10 14:39:46 -08:00
parent 6aae68ead4
commit 6f37bb40d9
5 changed files with 87 additions and 47 deletions

View File

@ -8,6 +8,9 @@
#import <AsyncDisplayKit/ASDisplayNode.h>
extern NSString * const ASTransitionContextFromLayoutKey;
extern NSString * const ASTransitionContextToLayoutKey;
@protocol ASContextTransitioning <NSObject>
/**
@ -16,19 +19,19 @@
- (BOOL)isAnimated;
/**
* @abstract The destination layout being transitioned to
* @abstract Retrieve either the "from" or "to" layout
*/
- (ASLayout *)layout;
- (ASLayout *)layoutForKey:(NSString *)key;
/**
* @abstrat The destination constrainedSize being transitioned to
* @abstract Retrieve either the "from" or "to" constrainedSize
*/
- (ASSizeRange)constrainedSize;
- (ASSizeRange)constrainedSizeForKey:(NSString *)key;
/**
* @abstract Subnodes in the new layout
* @abstract Retrieve the subnodes from either the "from" or "to" layout
*/
- (NSArray<ASDisplayNode *> *)subnodes;
- (NSArray<ASDisplayNode *> *)subnodesForKey:(NSString *)key;
/**
* @abstract Subnodes that have been inserted in the layout transition

View File

@ -610,34 +610,43 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
{
return [self measureWithSizeRange:constrainedSize completion:^(ASLayout *pendingLayout, ASSizeRange constrainedSize) {
return [self measureWithSizeRange:constrainedSize completion:^{
if ([[self class] usesImplicitHierarchyManagement]) {
[self __implicitlyInsertSubnodes];
[self __implicitlyRemoveSubnodes];
}
[self __applyLayout:pendingLayout constrainedSize:constrainedSize];
[self __completeLayoutCalculation];
}];
}
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize completion:(void(^)(ASLayout *, ASSizeRange))completion
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize completion:(void(^)())completion
{
ASDisplayNodeAssertThreadAffinity(self);
ASDN::MutexLocker l(_propertyLock);
if (![self __shouldSize])
return nil;
ASLayout *pendingLayout = _layout;
// only calculate the size if
// - we haven't already
// - the constrained size range is different
if (!_flags.isMeasured || !ASSizeRangeEqualToSizeRange(constrainedSize, _constrainedSize)) {
pendingLayout = [self calculateLayoutThatFits:constrainedSize];
[self __calculateSubnodeOperationsWithPendingLayout:pendingLayout currentLayout:_layout];
completion(pendingLayout, constrainedSize);
_previousLayout = _layout;
_layout = [self calculateLayoutThatFits:constrainedSize];
ASDisplayNodeAssertTrue(_layout.layoutableObject == self);
ASDisplayNodeAssertTrue(_layout.size.width >= 0.0);
ASDisplayNodeAssertTrue(_layout.size.height >= 0.0);
_previousConstrainedSize = _constrainedSize;
_constrainedSize = constrainedSize;
[self __calculateSubnodeOperationsWithLayout:_layout previousLayout:_previousLayout];
_flags.isMeasured = YES;
completion();
}
return pendingLayout;
return _layout;
}
- (ASLayout *)transitionLayoutWithAnimation:(BOOL)animated
@ -648,50 +657,41 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
- (ASLayout *)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize animated:(BOOL)animated
{
return [self measureWithSizeRange:constrainedSize completion:^(ASLayout *pendingLayout, ASSizeRange constrainedSize) {
_transitionContext = [[_ASTransitionContext alloc] initWithLayout:pendingLayout
constrainedSize:constrainedSize
animated:animated
delegate:self];
return [self measureWithSizeRange:constrainedSize completion:^{
_transitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated delegate:self];
[self __implicitlyInsertSubnodes];
[self animateLayoutTransition:_transitionContext];
}];
}
- (void)__calculateSubnodeOperationsWithPendingLayout:(ASLayout *)pendingLayout currentLayout:(ASLayout *)currentLayout
- (void)__calculateSubnodeOperationsWithLayout:(ASLayout *)layout previousLayout:(ASLayout *)previousLayout
{
if (_layout) {
if (previousLayout) {
NSIndexSet *insertions, *deletions;
[currentLayout.immediateSublayouts asdk_diffWithArray:pendingLayout.immediateSublayouts
[previousLayout.immediateSublayouts asdk_diffWithArray:layout.immediateSublayouts
insertions:&insertions
deletions:&deletions
compareBlock:^BOOL(ASLayout *lhs, ASLayout *rhs) {
return ASObjectIsEqual(lhs.layoutableObject, rhs.layoutableObject);
}];
filterNodesInLayoutAtIndexes(pendingLayout, insertions, &_insertedSubnodes, &_insertedSubnodePositions);
filterNodesInLayoutAtIndexesWithIntersectingNodes(currentLayout,
filterNodesInLayoutAtIndexes(layout, insertions, &_insertedSubnodes, &_insertedSubnodePositions);
filterNodesInLayoutAtIndexesWithIntersectingNodes(previousLayout,
deletions,
_insertedSubnodes,
&_removedSubnodes,
&_removedSubnodePositions);
} else {
NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pendingLayout.immediateSublayouts count])];
filterNodesInLayoutAtIndexes(pendingLayout, indexes, &_insertedSubnodes, &_insertedSubnodePositions);
NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [layout.immediateSublayouts count])];
filterNodesInLayoutAtIndexes(layout, indexes, &_insertedSubnodes, &_insertedSubnodePositions);
_removedSubnodes = nil;
}
}
- (void)__applyLayout:(ASLayout *)layout constrainedSize:(ASSizeRange)constrainedSize
- (void)__completeLayoutCalculation
{
ASDisplayNodeAssertTrue(layout.layoutableObject == self);
ASDisplayNodeAssertTrue(layout.size.width >= 0.0);
ASDisplayNodeAssertTrue(layout.size.height >= 0.0);
_layout = layout;
_constrainedSize = constrainedSize;
_flags.isMeasured = YES;
_insertedSubnodes = nil;
_removedSubnodes = nil;
_previousLayout = nil;
[self calculatedLayoutDidChange];
// we generate placeholders at measureWithSizeRange: time so that a node is guaranteed
@ -777,7 +777,7 @@ static inline void filterNodesInLayoutAtIndexesWithIntersectingNodes(
- (void)didCompleteTransitionLayout:(id<ASContextTransitioning>)context
{
[self __implicitlyRemoveSubnodes];
[self __applyLayout:context.layout constrainedSize:context.constrainedSize];
[self __completeLayoutCalculation];
}
#pragma mark - Implicit node hierarchy managagment
@ -814,6 +814,27 @@ static inline void filterNodesInLayoutAtIndexesWithIntersectingNodes(
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
{
[self didCompleteTransitionLayout:context];

View File

@ -62,8 +62,12 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
// This is the desired contentsScale, not the scale at which the layer's contents should be displayed
CGFloat _contentsScaleForDisplay;
ASLayout *_previousLayout;
ASLayout *_layout;
ASSizeRange _previousConstrainedSize;
ASSizeRange _constrainedSize;
UIEdgeInsets _hitTestSlop;
NSMutableArray *_subnodes;

View File

@ -16,9 +16,13 @@
@protocol _ASTransitionContextDelegate <NSObject>
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context;
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context;
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context;
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key;
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key;
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete;
@end
@ -27,10 +31,6 @@
@property (assign, readonly, nonatomic, getter=isAnimated) BOOL animated;
@property (strong, readonly) ASLayout *layout;
@property (assign, readonly) ASSizeRange constrainedSize;
- (instancetype)initWithLayout:(ASLayout *)layout constrainedSize:(ASSizeRange)constrainedSize animated:(BOOL)animated delegate:(id<_ASTransitionContextDelegate>)delegate;
- (instancetype)initWithAnimation:(BOOL)animated delegate:(id<_ASTransitionContextDelegate>)delegate;
@end

View File

@ -10,6 +10,10 @@
#import "ASLayout.h"
NSString * const ASTransitionContextFromLayoutKey = @"org.asyncdisplaykit.ASTransitionContextFromLayoutKey";
NSString * const ASTransitionContextToLayoutKey = @"org.asyncdisplaykit.ASTransitionContextToLayoutKey";
@interface _ASTransitionContext ()
@property (weak, nonatomic) id<_ASTransitionContextDelegate> delegate;
@ -18,12 +22,10 @@
@implementation _ASTransitionContext
- (instancetype)initWithLayout:(ASLayout *)layout constrainedSize:(ASSizeRange)constrainedSize animated:(BOOL)animated delegate:(id<_ASTransitionContextDelegate>)delegate
- (instancetype)initWithAnimation:(BOOL)animated delegate:(id<_ASTransitionContextDelegate>)delegate
{
self = [super init];
if (self) {
_layout = layout;
_constrainedSize = constrainedSize;
_animated = animated;
_delegate = delegate;
}
@ -32,6 +34,16 @@
#pragma mark - ASContextTransitioning Protocol Implementation
- (ASLayout *)layoutForKey:(NSString *)key
{
return [_delegate transitionContext:self layoutForKey:key];
}
- (ASSizeRange)constrainedSizeForKey:(NSString *)key
{
return [_delegate transitionContext:self constrainedSizeForKey:key];
}
- (CGRect)initialFrameForNode:(ASDisplayNode *)node
{
for (ASDisplayNode *subnode in [_delegate currentSubnodesWithTransitionContext:self]) {
@ -44,7 +56,7 @@
- (CGRect)finalFrameForNode:(ASDisplayNode *)node
{
for (ASLayout *layout in _layout.sublayouts) {
for (ASLayout *layout in [self layoutForKey:ASTransitionContextToLayoutKey].sublayouts) {
if (layout.layoutableObject == node) {
return [layout frame];
}
@ -52,10 +64,10 @@
return CGRectZero;
}
- (NSArray<ASDisplayNode *> *)subnodes
- (NSArray<ASDisplayNode *> *)subnodesForKey:(NSString *)key
{
NSMutableArray<ASDisplayNode *> *subnodes = [NSMutableArray array];
for (ASLayout *sublayout in _layout.immediateSublayouts) {
for (ASLayout *sublayout in [self layoutForKey:key].immediateSublayouts) {
[subnodes addObject:(ASDisplayNode *)sublayout.layoutableObject];
}
return subnodes;