Remove ASLayoutChild. ASLayout now has a position property defaults to (NAN, NAN).

This commit is contained in:
Huy Nguyen
2015-06-30 17:10:17 +07:00
parent e74823bbee
commit 4799a9d206
11 changed files with 79 additions and 54 deletions

View File

@@ -1426,8 +1426,8 @@ static NSInteger incrementIfFound(NSInteger i) {
subnodeSize.width, subnodeSize.height); subnodeSize.width, subnodeSize.height);
} }
for (ASLayoutChild *child in context.layout.children) { for (ASLayout *child in context.layout.children) {
stack.push({child.layout, context.absolutePosition + child.position, NO}); stack.push({child, context.absolutePosition + child.position, NO});
} }
} }
} }

View File

@@ -44,14 +44,16 @@
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
{ {
ASLayout *contentsLayout = [_child calculateLayoutThatFits:constrainedSize]; ASLayout *contentsLayout = [_child calculateLayoutThatFits:constrainedSize];
contentsLayout.position = CGPointZero;
NSMutableArray *children = [NSMutableArray arrayWithCapacity:2]; NSMutableArray *children = [NSMutableArray arrayWithCapacity:2];
if (_background) { if (_background) {
// Size background to exactly the same size. // Size background to exactly the same size.
ASLayout *backgroundLayout = [_background calculateLayoutThatFits:{contentsLayout.size, contentsLayout.size}]; ASLayout *backgroundLayout = [_background calculateLayoutThatFits:{contentsLayout.size, contentsLayout.size}];
[children addObject:[ASLayoutChild newWithPosition:{0,0} layout:backgroundLayout]]; backgroundLayout.position = CGPointZero;
[children addObject:backgroundLayout];
} }
[children addObject:[ASLayoutChild newWithPosition:{0,0} layout:contentsLayout]]; [children addObject:contentsLayout];
return [ASLayout newWithLayoutableObject:self size:contentsLayout.size children:children]; return [ASLayout newWithLayoutableObject:self size:contentsLayout.size children:children];
} }

View File

@@ -67,14 +67,12 @@
// Compute the centered postion for the child // Compute the centered postion for the child
BOOL shouldCenterAlongX = (_centeringOptions & ASCenterLayoutNodeCenteringX); BOOL shouldCenterAlongX = (_centeringOptions & ASCenterLayoutNodeCenteringX);
BOOL shouldCenterAlongY = (_centeringOptions & ASCenterLayoutNodeCenteringY); BOOL shouldCenterAlongY = (_centeringOptions & ASCenterLayoutNodeCenteringY);
const CGPoint childPosition = { childLayout.position = {
ASRoundPixelValue(shouldCenterAlongX ? (size.width - childLayout.size.width) * 0.5f : 0), ASRoundPixelValue(shouldCenterAlongX ? (size.width - childLayout.size.width) * 0.5f : 0),
ASRoundPixelValue(shouldCenterAlongY ? (size.height - childLayout.size.height) * 0.5f : 0) ASRoundPixelValue(shouldCenterAlongY ? (size.height - childLayout.size.height) * 0.5f : 0)
}; };
return [ASLayout newWithLayoutableObject:self return [ASLayout newWithLayoutableObject:self size:size children:@[childLayout]];
size:size
children:@[[ASLayoutChild newWithPosition:childPosition layout:childLayout]]];
} }
@end @end

View File

@@ -99,9 +99,10 @@ static CGFloat centerInset(CGFloat outer, CGFloat inner)
constrainedSize.max.height - constrainedSize.max.height -
(finite(_insets.bottom, (finite(_insets.bottom,
centerInset(constrainedSize.max.height, childLayout.size.height)) + childLayout.size.height)); centerInset(constrainedSize.max.height, childLayout.size.height)) + childLayout.size.height));
return [ASLayout newWithLayoutableObject:self
size:computedSize childLayout.position = CGPointMake(x, y);
children:@[[ASLayoutChild newWithPosition:{x,y} layout:childLayout]]];
return [ASLayout newWithLayoutableObject:self size:computedSize children:@[childLayout]];
} }
@end @end

View File

@@ -12,35 +12,45 @@
#import <AsyncDisplayKit/ASAssert.h> #import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASLayoutable.h> #import <AsyncDisplayKit/ASLayoutable.h>
/** Represents the computed size of a layout node, as well as the computed sizes and positions of its children. */ extern CGPoint const CGPointNull;
extern BOOL CGPointIsNull(CGPoint point);
/** Represents a computed immutable layout tree. */
@interface ASLayout : NSObject @interface ASLayout : NSObject
@property (nonatomic, readonly) id<ASLayoutable> layoutableObject; @property (nonatomic, readonly) id<ASLayoutable> layoutableObject;
@property (nonatomic, readonly) CGSize size; @property (nonatomic, readonly) CGSize size;
/** /**
* Each item is of type ASLayoutChild. * Position parent (if any). Default to CGPointNull.
*
* @discussion Before being used as a child layout, this property must be set and no longer equal CGPointNull.
*
* @discussion Unlike all other properties, this property is read-write because often by initializaion time, it has yet been determined.
* To enforce immutability, this property can be set once and only once.
*
*/
@property (nonatomic, readwrite) CGPoint position;
/**
* Array of ASLayout children. Each child must have a valid non-null position.
*/ */
@property (nonatomic, readonly) NSArray *children; @property (nonatomic, readonly) NSArray *children;
+ (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject + (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject
size:(CGSize)size size:(CGSize)size
position:(CGPoint)position
children:(NSArray *)children; children:(NSArray *)children;
/** /**
* Convenience that does not have any children. * Convenience that has CGPointNull position.
*/
+ (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject
size:(CGSize)size
children:(NSArray *)children;
/**
* Convenience that has CGPointNull position and no children.
*/ */
+ (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject size:(CGSize)size; + (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject size:(CGSize)size;
@end @end
@interface ASLayoutChild : NSObject
@property (nonatomic, readonly) CGPoint position;
@property (nonatomic, readonly) ASLayout *layout;
/**
* Designated initializer
*/
+ (instancetype)newWithPosition:(CGPoint)position layout:(ASLayout *)layout;
@end

View File

@@ -9,39 +9,53 @@
*/ */
#import "ASLayout.h" #import "ASLayout.h"
#import "ASAssert.h"
CGPoint const CGPointNull = {NAN, NAN};
extern BOOL CGPointIsNull(CGPoint point)
{
return isnan(point.x) && isnan(point.y);
}
@implementation ASLayout @implementation ASLayout
+ (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject + (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject
size:(CGSize)size size:(CGSize)size
position:(CGPoint)position
children:(NSArray *)children children:(NSArray *)children
{ {
for (ASLayout *child in children) {
ASDisplayNodeAssert(!CGPointIsNull(child.position), @"Invalid position is not allowed in children.");
}
ASLayout *l = [super new]; ASLayout *l = [super new];
if (l) { if (l) {
l->_layoutableObject = layoutableObject; l->_layoutableObject = layoutableObject;
l->_size = size; l->_size = size;
l->_position = position;
l->_children = [children copy]; l->_children = [children copy];
} }
return l; return l;
} }
+ (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject
size:(CGSize)size
children:(NSArray *)children
{
return [self newWithLayoutableObject:layoutableObject size:size position:CGPointNull children:children];
}
+ (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject size:(CGSize)size + (instancetype)newWithLayoutableObject:(id<ASLayoutable>)layoutableObject size:(CGSize)size
{ {
return [self newWithLayoutableObject:layoutableObject size:size children:nil]; return [self newWithLayoutableObject:layoutableObject size:size children:nil];
} }
@end - (void)setPosition:(CGPoint)position
@implementation ASLayoutChild
+ (instancetype)newWithPosition:(CGPoint)position layout:(ASLayout *)layout
{ {
ASLayoutChild *c = [super new]; ASDisplayNodeAssert(CGPointIsNull(_position), @"Position can be set once and only once.");
if (c) { ASDisplayNodeAssert(!CGPointIsNull(position), @"Position must not be set to null.");
c->_position = position; _position = position;
c->_layout = layout;
}
return c;
} }
@end @end

View File

@@ -41,10 +41,12 @@
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
{ {
ASLayout *contentsLayout = [_child calculateLayoutThatFits:constrainedSize]; ASLayout *contentsLayout = [_child calculateLayoutThatFits:constrainedSize];
NSMutableArray *layoutChildren = [NSMutableArray arrayWithObject:[ASLayoutChild newWithPosition:{0, 0} layout:contentsLayout]]; contentsLayout.position = CGPointZero;
NSMutableArray *layoutChildren = [NSMutableArray arrayWithObject:contentsLayout];
if (_overlay) { if (_overlay) {
ASLayout *overlayLayout = [_overlay calculateLayoutThatFits:{contentsLayout.size, contentsLayout.size}]; ASLayout *overlayLayout = [_overlay calculateLayoutThatFits:{contentsLayout.size, contentsLayout.size}];
[layoutChildren addObject:[ASLayoutChild newWithPosition:{0, 0} layout:overlayLayout]]; overlayLayout.position = CGPointZero;
[layoutChildren addObject:overlayLayout];
} }
return [ASLayout newWithLayoutableObject:self size:contentsLayout.size children:layoutChildren]; return [ASLayout newWithLayoutableObject:self size:contentsLayout.size children:layoutChildren];

View File

@@ -68,9 +68,8 @@
// If there is no max size in *either* dimension, we can't apply the ratio, so just pass our size range through. // If there is no max size in *either* dimension, we can't apply the ratio, so just pass our size range through.
const ASSizeRange childRange = (bestSize == sizeOptions.end()) ? constrainedSize : ASSizeRangeMake(*bestSize, *bestSize); const ASSizeRange childRange = (bestSize == sizeOptions.end()) ? constrainedSize : ASSizeRangeMake(*bestSize, *bestSize);
ASLayout *childLayout = [_child calculateLayoutThatFits:childRange]; ASLayout *childLayout = [_child calculateLayoutThatFits:childRange];
return [ASLayout newWithLayoutableObject:self childLayout.position = CGPointZero;
size:childLayout.size return [ASLayout newWithLayoutableObject:self size:childLayout.size children:@[childLayout]];
children:@[[ASLayoutChild newWithPosition:{0, 0} layout:childLayout]]];
} }
@end @end

View File

@@ -68,22 +68,22 @@
ASSizeRange childConstraint = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, child.size) ASSizeRange childConstraint = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, child.size)
? ASSizeRangeMake({0, 0}, autoMaxSize) ? ASSizeRangeMake({0, 0}, autoMaxSize)
: ASRelativeSizeRangeResolve(child.size, size); : ASRelativeSizeRangeResolve(child.size, size);
ASLayoutChild *layoutChild = [ASLayoutChild newWithPosition:child.position ASLayout *childLayout = [child.node calculateLayoutThatFits:childConstraint];
layout:[child.node calculateLayoutThatFits:childConstraint]]; childLayout.position = child.position;
[layoutChildren addObject:layoutChild]; [layoutChildren addObject:childLayout];
} }
if (isnan(size.width)) { if (isnan(size.width)) {
size.width = constrainedSize.min.width; size.width = constrainedSize.min.width;
for (ASLayoutChild *child in layoutChildren) { for (ASLayout *child in layoutChildren) {
size.width = MAX(size.width, child.position.x + child.layout.size.width); size.width = MAX(size.width, child.position.x + child.size.width);
} }
} }
if (isnan(size.height)) { if (isnan(size.height)) {
size.height = constrainedSize.min.height; size.height = constrainedSize.min.height;
for (ASLayoutChild *child in layoutChildren) { for (ASLayout *child in layoutChildren) {
size.height = MAX(size.height, child.position.y + child.layout.size.height); size.height = MAX(size.height, child.position.y + child.size.height);
} }
} }

View File

@@ -15,7 +15,7 @@
/** Represents a set of laid out and positioned stack layout children. */ /** Represents a set of laid out and positioned stack layout children. */
struct ASStackPositionedLayout { struct ASStackPositionedLayout {
const std::vector<ASLayoutChild *> children; const std::vector<ASLayout *> children;
const CGFloat crossSize; const CGFloat crossSize;
/** Given an unpositioned layout, computes the positions each child should be placed at. */ /** Given an unpositioned layout, computes the positions each child should be placed at. */

View File

@@ -47,16 +47,15 @@ static ASStackPositionedLayout stackedLayout(const ASStackLayoutNodeStyle &style
CGPoint p = directionPoint(style.direction, offset, 0); CGPoint p = directionPoint(style.direction, offset, 0);
BOOL first = YES; BOOL first = YES;
auto stackedChildren = AS::map(unpositionedLayout.items, [&](const ASStackUnpositionedItem &l) -> ASLayoutChild *{ auto stackedChildren = AS::map(unpositionedLayout.items, [&](const ASStackUnpositionedItem &l) -> ASLayout *{
p = p + directionPoint(style.direction, l.child.spacingBefore, 0); p = p + directionPoint(style.direction, l.child.spacingBefore, 0);
if (!first) { if (!first) {
p = p + directionPoint(style.direction, style.spacing, 0); p = p + directionPoint(style.direction, style.spacing, 0);
} }
first = NO; first = NO;
ASLayoutChild *c = [ASLayoutChild newWithPosition:p + directionPoint(style.direction, 0, crossOffset(style, l, crossSize)) l.layout.position = p + directionPoint(style.direction, 0, crossOffset(style, l, crossSize));
layout:l.layout];
p = p + directionPoint(style.direction, stackDimension(style.direction, l.layout.size) + l.child.spacingAfter, 0); p = p + directionPoint(style.direction, stackDimension(style.direction, l.layout.size) + l.child.spacingAfter, 0);
return c; return l.layout;
}); });
return {stackedChildren, crossSize}; return {stackedChildren, crossSize};
} }