Addressed comments to LayoutOptions PR

This commit is contained in:
rcancro
2015-09-11 16:07:18 -07:00
parent dc0d22dff4
commit b14e189bfb
20 changed files with 324 additions and 135 deletions

View File

@@ -44,6 +44,7 @@
@implementation ASDisplayNode @implementation ASDisplayNode
// these dynamic properties all defined in ASLayoutOptionsPrivate.m
@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions; @dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions;
@synthesize preferredFrameSize = _preferredFrameSize; @synthesize preferredFrameSize = _preferredFrameSize;
@synthesize isFinalLayoutable = _isFinalLayoutable; @synthesize isFinalLayoutable = _isFinalLayoutable;

View File

@@ -68,4 +68,15 @@ static NSString * const kBackgroundChildKey = @"kBackgroundChildKey";
return [super childForIdentifier:kBackgroundChildKey]; return [super childForIdentifier:kBackgroundChildKey];
} }
- (void)setChildren:(NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
}
- (NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
return nil;
}
@end @end

View File

@@ -90,4 +90,15 @@
return [ASLayout layoutWithLayoutableObject:self size:size sublayouts:@[sublayout]]; return [ASLayout layoutWithLayoutableObject:self size:size sublayouts:@[sublayout]];
} }
- (void)setChildren:(NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
}
- (NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
return nil;
}
@end @end

View File

@@ -109,4 +109,15 @@ static CGFloat centerInset(CGFloat outer, CGFloat inner)
return [ASLayout layoutWithLayoutableObject:self size:computedSize sublayouts:@[sublayout]]; return [ASLayout layoutWithLayoutableObject:self size:computedSize sublayouts:@[sublayout]];
} }
- (void)setChildren:(NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
}
- (NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
return nil;
}
@end @end

View File

@@ -12,8 +12,7 @@
@protocol ASLayoutable; @protocol ASLayoutable;
#import <AsyncDisplayKit/ASStackLayoutable.h> #import <AsyncDisplayKit/ASLayoutSpec.h>
#import <AsyncDisplayKit/ASStaticLayoutable.h>
@interface ASLayoutOptions : NSObject <ASStackLayoutable, ASStaticLayoutable, NSCopying> @interface ASLayoutOptions : NSObject <ASStackLayoutable, ASStaticLayoutable, NSCopying>
@@ -24,8 +23,7 @@
- (void)setValuesFromLayoutable:(id<ASLayoutable>)layoutable; - (void)setValuesFromLayoutable:(id<ASLayoutable>)layoutable;
#pragma mark - Subclasses should implement these! #pragma mark - Subclasses should implement these!
- (void)setupDefaults; - (void)propogateOptionsFromLayoutOptions:(ASLayoutOptions *)layoutOptions;
- (void)copyIntoOptions:(ASLayoutOptions *)layoutOptions;
#pragma mark - ASStackLayoutable #pragma mark - ASStackLayoutable
@@ -43,5 +41,4 @@
@property (nonatomic, readwrite) ASRelativeSizeRange sizeRange; @property (nonatomic, readwrite) ASRelativeSizeRange sizeRange;
@property (nonatomic, readwrite) CGPoint layoutPosition; @property (nonatomic, readwrite) CGPoint layoutPosition;
@end @end

View File

@@ -63,7 +63,20 @@ static Class gDefaultLayoutOptionsClass = nil;
{ {
self = [super init]; self = [super init];
if (self) { if (self) {
[self setupDefaults];
self.flexBasis = ASRelativeDimensionUnconstrained;
self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero));
self.layoutPosition = CGPointZero;
// The following properties use a default value of 0 which we do not need to assign.
// self.spacingBefore = 0;
// self.spacingAfter = 0;
// self.flexGrow = NO;
// self.flexShrink = NO;
// self.alignSelf = ASStackLayoutAlignSelfAuto;
// self.ascender = 0;
// self.descender = 0;
[self setValuesFromLayoutable:layoutable]; [self setValuesFromLayoutable:layoutable];
} }
return self; return self;
@@ -73,59 +86,57 @@ static Class gDefaultLayoutOptionsClass = nil;
- (id)copyWithZone:(NSZone *)zone - (id)copyWithZone:(NSZone *)zone
{ {
ASLayoutOptions *copy = [[[self class] alloc] init]; ASLayoutOptions *copy = [[[self class] alloc] init];
[self copyIntoOptions:copy]; [copy propogateOptionsFromLayoutOptions:self];
return copy; return copy;
} }
- (void)copyIntoOptions:(ASLayoutOptions *)copy - (void)propogateOptionsFromLayoutOptions:(ASLayoutOptions *)layoutOptions
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
copy.flexBasis = self.flexBasis; self.flexBasis = layoutOptions.flexBasis;
copy.spacingAfter = self.spacingAfter; self.spacingAfter = layoutOptions.spacingAfter;
copy.spacingBefore = self.spacingBefore; self.spacingBefore = layoutOptions.spacingBefore;
copy.flexGrow = self.flexGrow; self.flexGrow = layoutOptions.flexGrow;
copy.flexShrink = self.flexShrink; self.flexShrink = layoutOptions.flexShrink;
copy.ascender = self.ascender; self.ascender = layoutOptions.ascender;
copy.descender = self.descender; self.descender = layoutOptions.descender;
copy.sizeRange = self.sizeRange; self.sizeRange = layoutOptions.sizeRange;
copy.layoutPosition = self.layoutPosition; self.layoutPosition = layoutOptions.layoutPosition;
} }
/**
#pragma mark - Defaults * Given an id<ASLayoutable>, set up layout options that are intrinsically defined by the layoutable.
- (void)setupDefaults *
{ * While this could be done in the layoutable object itself, moving the logic into the ASLayoutOptions class
self.flexBasis = ASRelativeDimensionUnconstrained; * allows a custom spec to set up defaults without needing to alter the layoutable itself. For example,
self.spacingBefore = 0; * image you were creating a custom baseline spec that needed ascender/descender. To assign values automatically
self.spacingAfter = 0; * when a text node's attribute string is set, you would need to subclass ASTextNode and assign the values in the
self.flexGrow = NO; * override of setAttributeString. However, assigning the defaults in an ASLayoutOptions subclass's
self.flexShrink = NO; * setValuesFromLayoutable allows you to create a custom spec without the need to create a
self.alignSelf = ASStackLayoutAlignSelfAuto; * subclass of ASTextNode.
*
self.ascender = 0; * @param layoutable The layoutable object to inspect for default intrinsic layout option values
self.descender = 0; */
self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero));
self.layoutPosition = CGPointZero;
}
// Do this here instead of in Node/Spec subclasses so that custom specs can set default values
- (void)setValuesFromLayoutable:(id<ASLayoutable>)layoutable - (void)setValuesFromLayoutable:(id<ASLayoutable>)layoutable
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
if ([layoutable isKindOfClass:[ASTextNode class]]) {
ASTextNode *textNode = (ASTextNode *)layoutable;
if (textNode.attributedString.length > 0) {
self.ascender = round([[textNode.attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * ASScreenScale())/ASScreenScale();
self.descender = round([[textNode.attributedString attribute:NSFontAttributeName atIndex:textNode.attributedString.length - 1 effectiveRange:NULL] descender] * ASScreenScale())/ASScreenScale();
}
}
if ([layoutable isKindOfClass:[ASDisplayNode class]]) { if ([layoutable isKindOfClass:[ASDisplayNode class]]) {
ASDisplayNode *displayNode = (ASDisplayNode *)layoutable; ASDisplayNode *displayNode = (ASDisplayNode *)layoutable;
self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize)); self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize));
self.layoutPosition = displayNode.frame.origin; self.layoutPosition = displayNode.frame.origin;
if ([layoutable isKindOfClass:[ASTextNode class]]) {
ASTextNode *textNode = (ASTextNode *)layoutable;
NSAttributedString *attributedString = textNode.attributedString;
if (attributedString.length > 0) {
CGFloat screenScale = ASScreenScale();
self.ascender = round([[attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
self.descender = round([[attributedString attribute:NSFontAttributeName atIndex:attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale;
}
}
} }
} }

View File

@@ -10,25 +10,24 @@
#import <AsyncDisplayKit/ASDisplayNode.h> #import <AsyncDisplayKit/ASDisplayNode.h>
#import <AsyncDisplayKit/ASLayoutSpec.h> #import <AsyncDisplayKit/ASLayoutSpec.h>
#import <AsyncDisplayKit/ASThread.h>
@interface ASDisplayNode()
{
ASLayoutOptions *_layoutOptions;
dispatch_once_t _layoutOptionsInitializeToken;
}
@end
@interface ASDisplayNode(ASLayoutOptions)<ASLayoutable> @interface ASDisplayNode(ASLayoutOptions)<ASLayoutable>
@end @end
@interface ASLayoutSpec() @interface ASDisplayNode()
{ {
ASLayoutOptions *_layoutOptions; ASLayoutOptions *_layoutOptions;
dispatch_once_t _layoutOptionsInitializeToken; ASDN::RecursiveMutex _layoutOptionsLock;
} }
@end @end
@interface ASLayoutSpec(ASLayoutOptions)<ASLayoutable> @interface ASLayoutSpec(ASLayoutOptions)<ASLayoutable>
@end @end
@interface ASLayoutSpec()
{
ASLayoutOptions *_layoutOptions;
ASDN::RecursiveMutex _layoutOptionsLock;
}
@end

View File

@@ -10,16 +10,27 @@
#import "ASLayoutOptionsPrivate.h" #import "ASLayoutOptionsPrivate.h"
#import <AsyncDisplayKit/ASDisplayNodeInternal.h> #import <AsyncDisplayKit/ASDisplayNodeInternal.h>
#import "ASThread.h"
/**
* Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties
* in ASLayoutable that are used as layoutOptions when a node or spec is used in a layout spec.
* These properties are provided for convenience, as they are forwards to the node or spec's
* ASLayoutOptions class. Instead of duplicating the property forwarding in both classes, we
* create a define that allows us to easily implement the forwards in one place.
*
* If you create a custom layout spec, we recommend this stragety if you decide to extend
* ASDisplayNode and ASLAyoutSpec to provide convenience properties for any options that your
* layoutSpec may require.
*/
#define ASLayoutOptionsForwarding \ #define ASLayoutOptionsForwarding \
- (ASLayoutOptions *)layoutOptions\ - (ASLayoutOptions *)layoutOptions\
{\ {\
dispatch_once(&_layoutOptionsInitializeToken, ^{\ ASDN::MutexLocker l(_layoutOptionsLock);\
if (_layoutOptions == nil) {\ if (_layoutOptions == nil) {\
_layoutOptions = [[[ASLayoutOptions defaultLayoutOptionsClass] alloc] initWithLayoutable:self];\ _layoutOptions = [[[ASLayoutOptions defaultLayoutOptionsClass] alloc] initWithLayoutable:self];\
}\ }\
});\
return _layoutOptions;\ return _layoutOptions;\
}\ }\
\ \

View File

@@ -22,10 +22,37 @@
- (instancetype)init; - (instancetype)init;
/**
* Set child methods
*
* Every ASLayoutSpec must act on at least one child. The ASLayoutSpec base class takes the
* reponsibility of holding on to the spec children. For a layout spec like ASInsetLayoutSpec that
* only requires a single child, the child can be added by calling setChild:.
*
* For layout specs that require a known number of children (ASBackgroundLayoutSpec, for example)
* a subclass should use the setChild to set the "primary" child. It can then use setChild:forIdentifier:
* to set any other required children. Ideally a subclass would hide this from the user, and use the
* setChildWithIdentifier: internally. For example, ASBackgroundLayoutSpec exposes a backgroundChild
* property that behind the scenes is calling setChild:forIdentifier:.
*
* Finally, a layout spec like ASStackLayoutSpec can take an unknown number of children. In this case,
* the setChildren: method should be used. For good measure, in these layout specs it probably makes
* sense to define setChild: to do something appropriate or to assert.
*/
- (void)setChild:(id<ASLayoutable>)child; - (void)setChild:(id<ASLayoutable>)child;
- (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier; - (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier;
- (void)setChildren:(NSArray *)children; - (void)setChildren:(NSArray *)children;
/**
* Get child methods
*
* There is a corresponding "getChild" method for the above "setChild" methods. If a subclass
* has extra layoutable children, it is recommended to make a corresponding get method for that
* child. For example, the ASBackgroundLayoutSpec responds to backgroundChild.
*
* If a get method is called on a spec that doesn't make sense, then the standard is to assert.
* For example, calling children on an ASInsetLayoutSpec will assert.
*/
- (id<ASLayoutable>)child; - (id<ASLayoutable>)child;
- (id<ASLayoutable>)childForIdentifier:(NSString *)identifier; - (id<ASLayoutable>)childForIdentifier:(NSString *)identifier;
- (NSArray *)children; - (NSArray *)children;

View File

@@ -17,6 +17,7 @@
#import "ASLayout.h" #import "ASLayout.h"
#import "ASLayoutOptions.h" #import "ASLayoutOptions.h"
#import "ASLayoutOptionsPrivate.h" #import "ASLayoutOptionsPrivate.h"
#import "ASThread.h"
#import <objc/runtime.h> #import <objc/runtime.h>
@@ -29,6 +30,7 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
@implementation ASLayoutSpec @implementation ASLayoutSpec
// these dynamic properties all defined in ASLayoutOptionsPrivate.m
@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions; @dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions;
@synthesize layoutChildren = _layoutChildren; @synthesize layoutChildren = _layoutChildren;
@synthesize isFinalLayoutable = _isFinalLayoutable; @synthesize isFinalLayoutable = _isFinalLayoutable;
@@ -80,8 +82,7 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
id<ASLayoutable> finalLayoutable = [child finalLayoutable]; id<ASLayoutable> finalLayoutable = [child finalLayoutable];
if (finalLayoutable != child) { if (finalLayoutable != child) {
ASLayoutOptions *layoutOptions = [child layoutOptions]; [finalLayoutable.layoutOptions propogateOptionsFromLayoutOptions:child.layoutOptions];
[layoutOptions copyIntoOptions:finalLayoutable.layoutOptions];
return finalLayoutable; return finalLayoutable;
} }
} }

View File

@@ -20,11 +20,22 @@
@class ASLayoutSpec; @class ASLayoutSpec;
/** /**
* The ASLayoutable protocol declares a method for measuring the layout of an object. A class must implement the method * The ASLayoutable protocol declares a method for measuring the layout of an object. A layout
* so that instances of that class can be used to build layout trees. The protocol also provides information * is defined by an ASLayout return value, and must specify 1) the size (but not position) of the
* about how an object should be laid out within an ASStackLayoutSpec. * layoutable object, and 2) the size and position of all of its immediate child objects. The tree
* recursion is driven by parents requesting layouts from their children in order to determine their
* size, followed by the parents setting the position of the children once the size is known
*
* The protocol also implements a "family" of Layoutable protocols. These protocols contain layout
* options that can be used for specific layout specs. For example, ASStackLayoutSpec has options
* defining how a layoutable should shrink or grow based upon available space.
*
* These layout options are all stored in an ASLayoutOptions class (that is defined in ASLayoutablePrivate).
* Generally you needn't worry about the layout options class, as the layoutable protocols allow all direct
* access to the options via convenience properties. If you are creating custom layout spec, then you can
* extend the backing layout options class to accomodate any new layout options.
*/ */
@protocol ASLayoutable <ASLayoutablePrivate, ASStackLayoutable, ASStaticLayoutable> @protocol ASLayoutable <ASStackLayoutable, ASStaticLayoutable, ASLayoutablePrivate>
/** /**
* @abstract Calculate a layout based on given size range. * @abstract Calculate a layout based on given size range.
@@ -35,4 +46,64 @@
*/ */
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize; - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize;
#pragma mark - Layout options from the Layoutable Protocols
#pragma mark - ASStackLayoutable
/**
* @abstract Additional space to place before this object in the stacking direction.
* Used when attached to a stack layout.
*/
@property (nonatomic, readwrite) CGFloat spacingBefore;
/**
* @abstract Additional space to place after this object in the stacking direction.
* Used when attached to a stack layout.
*/
@property (nonatomic, readwrite) CGFloat spacingAfter;
/**
* @abstract If the sum of childrens' stack dimensions is less than the minimum size, should this object grow?
* Used when attached to a stack layout.
*/
@property (nonatomic, readwrite) BOOL flexGrow;
/**
* @abstract If the sum of childrens' stack dimensions is greater than the maximum size, should this object shrink?
* Used when attached to a stack layout.
*/
@property (nonatomic, readwrite) BOOL flexShrink;
/**
* @abstract Specifies the initial size in the stack dimension for this object.
* Default to ASRelativeDimensionUnconstrained.
* Used when attached to a stack layout.
*/
@property (nonatomic, readwrite) ASRelativeDimension flexBasis;
/**
* @abstract Orientation of the object along cross axis, overriding alignItems
* Used when attached to a stack layout.
*/
@property (nonatomic, readwrite) ASStackLayoutAlignSelf alignSelf;
/**
* @abstract Used for baseline alignment. The distance from the top of the object to its baseline.
*/
@property (nonatomic, readwrite) CGFloat ascender;
/**
* @abstract Used for baseline alignment. The distance from the baseline of the object to its bottom.
*/
@property (nonatomic, readwrite) CGFloat descender;
#pragma mark - ASStaticLayoutable
/**
If specified, the child's size is restricted according to this size. Percentages are resolved relative to the static layout spec.
*/
@property (nonatomic, assign) ASRelativeSizeRange sizeRange;
/** The position of this object within its parent spec. */
@property (nonatomic, assign) CGPoint layoutPosition;
@end @end

View File

@@ -61,4 +61,15 @@ static NSString * const kOverlayChildKey = @"kOverlayChildKey";
return [ASLayout layoutWithLayoutableObject:self size:contentsLayout.size sublayouts:sublayouts]; return [ASLayout layoutWithLayoutableObject:self size:contentsLayout.size sublayouts:sublayouts];
} }
- (void)setChildren:(NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
}
- (NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
return nil;
}
@end @end

View File

@@ -75,4 +75,15 @@
return [ASLayout layoutWithLayoutableObject:self size:sublayout.size sublayouts:@[sublayout]]; return [ASLayout layoutWithLayoutableObject:self size:sublayout.size sublayouts:@[sublayout]];
} }
- (void)setChildren:(NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
}
- (NSArray *)children
{
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
return nil;
}
@end @end

View File

@@ -87,6 +87,12 @@
ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports setChildren"); ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports setChildren");
} }
- (id<ASLayoutable>)childForIdentifier:(NSString *)identifier
{
ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports children");
return nil;
}
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
{ {
ASStackLayoutSpecStyle style = {.direction = _direction, .spacing = _spacing, .justifyContent = _justifyContent, .alignItems = _alignItems, .baselineRelativeArrangement = _baselineRelativeArrangement}; ASStackLayoutSpecStyle style = {.direction = _direction, .spacing = _spacing, .justifyContent = _justifyContent, .alignItems = _alignItems, .baselineRelativeArrangement = _baselineRelativeArrangement};

View File

@@ -47,16 +47,15 @@
NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:self.children.count]; NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:self.children.count];
for (id<ASLayoutable> child in self.children) { for (id<ASLayoutable> child in self.children) {
ASLayoutOptions *layoutOptions = child.layoutOptions;
CGSize autoMaxSize = { CGSize autoMaxSize = {
constrainedSize.max.width - layoutOptions.layoutPosition.x, constrainedSize.max.width - child.layoutPosition.x,
constrainedSize.max.height - layoutOptions.layoutPosition.y constrainedSize.max.height - child.layoutPosition.y
}; };
ASSizeRange childConstraint = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, layoutOptions.sizeRange) ASSizeRange childConstraint = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, child.sizeRange)
? ASSizeRangeMake({0, 0}, autoMaxSize) ? ASSizeRangeMake({0, 0}, autoMaxSize)
: ASRelativeSizeRangeResolve(layoutOptions.sizeRange, size); : ASRelativeSizeRangeResolve(child.sizeRange, size);
ASLayout *sublayout = [child measureWithSizeRange:childConstraint]; ASLayout *sublayout = [child measureWithSizeRange:childConstraint];
sublayout.position = layoutOptions.layoutPosition; sublayout.position = child.layoutPosition;
[sublayouts addObject:sublayout]; [sublayouts addObject:sublayout];
} }
@@ -79,4 +78,15 @@
sublayouts:sublayouts]; sublayouts:sublayouts];
} }
- (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier
{
ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports setChildren");
}
- (id<ASLayoutable>)childForIdentifier:(NSString *)identifier
{
ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports children");
return nil;
}
@end @end

View File

@@ -20,9 +20,9 @@ static CGFloat baselineForItem(const ASStackLayoutSpecStyle &style,
__weak id<ASLayoutable> child = layout.layoutableObject; __weak id<ASLayoutable> child = layout.layoutableObject;
switch (style.alignItems) { switch (style.alignItems) {
case ASStackLayoutAlignItemsBaselineFirst: case ASStackLayoutAlignItemsBaselineFirst:
return child.layoutOptions.ascender; return child.ascender;
case ASStackLayoutAlignItemsBaselineLast: case ASStackLayoutAlignItemsBaselineLast:
return layout.size.height + child.layoutOptions.descender; return layout.size.height + child.descender;
default: default:
return 0; return 0;
} }
@@ -38,7 +38,7 @@ static CGFloat baselineOffset(const ASStackLayoutSpecStyle &style,
__weak id<ASLayoutable> child = l.layoutableObject; __weak id<ASLayoutable> child = l.layoutableObject;
switch (style.alignItems) { switch (style.alignItems) {
case ASStackLayoutAlignItemsBaselineFirst: case ASStackLayoutAlignItemsBaselineFirst:
return maxAscender - child.layoutOptions.ascender; return maxAscender - child.ascender;
case ASStackLayoutAlignItemsBaselineLast: case ASStackLayoutAlignItemsBaselineLast:
return maxBaseline - baselineForItem(style, l); return maxBaseline - baselineForItem(style, l);
@@ -91,9 +91,9 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A
our layoutSpec to have it so that it can be baseline aligned with another text node or baseline layout spec. our layoutSpec to have it so that it can be baseline aligned with another text node or baseline layout spec.
*/ */
const auto ascenderIt = std::max_element(positionedLayout.sublayouts.begin(), positionedLayout.sublayouts.end(), [&](const ASLayout *a, const ASLayout *b){ const auto ascenderIt = std::max_element(positionedLayout.sublayouts.begin(), positionedLayout.sublayouts.end(), [&](const ASLayout *a, const ASLayout *b){
return a.layoutableObject.layoutOptions.ascender < b.layoutableObject.layoutOptions.ascender; return a.layoutableObject.ascender < b.layoutableObject.ascender;
}); });
const CGFloat maxAscender = baselineIt == positionedLayout.sublayouts.end() ? 0 : (*ascenderIt).layoutableObject.layoutOptions.ascender; const CGFloat maxAscender = baselineIt == positionedLayout.sublayouts.end() ? 0 : (*ascenderIt).layoutableObject.ascender;
/* /*
Step 3: Take each child and update its layout position based on the baseline offset. Step 3: Take each child and update its layout position based on the baseline offset.
@@ -107,7 +107,7 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A
BOOL first = YES; BOOL first = YES;
auto stackedChildren = AS::map(positionedLayout.sublayouts, [&](ASLayout *l) -> ASLayout *{ auto stackedChildren = AS::map(positionedLayout.sublayouts, [&](ASLayout *l) -> ASLayout *{
__weak id<ASLayoutable> child = l.layoutableObject; __weak id<ASLayoutable> child = l.layoutableObject;
p = p + directionPoint(style.direction, child.layoutOptions.spacingBefore, 0); p = p + directionPoint(style.direction, child.spacingBefore, 0);
if (first) { if (first) {
// if this is the first item use the previously computed start point // if this is the first item use the previously computed start point
p = l.position; p = l.position;
@@ -124,9 +124,9 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A
// node from baselines and not bounding boxes. // node from baselines and not bounding boxes.
CGFloat spacingAfterBaseline = 0; CGFloat spacingAfterBaseline = 0;
if (style.direction == ASStackLayoutDirectionVertical) { if (style.direction == ASStackLayoutDirectionVertical) {
spacingAfterBaseline = child.layoutOptions.descender; spacingAfterBaseline = child.descender;
} }
p = p + directionPoint(style.direction, stackDimension(style.direction, l.size) + child.layoutOptions.spacingAfter + spacingAfterBaseline, 0); p = p + directionPoint(style.direction, stackDimension(style.direction, l.size) + child.spacingAfter + spacingAfterBaseline, 0);
return l; return l;
}); });
@@ -156,7 +156,7 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A
const auto descenderIt = std::max_element(stackedChildren.begin(), stackedChildren.end(), [&](const ASLayout *a, const ASLayout *b){ const auto descenderIt = std::max_element(stackedChildren.begin(), stackedChildren.end(), [&](const ASLayout *a, const ASLayout *b){
return a.position.y + a.size.height < b.position.y + b.size.height; return a.position.y + a.size.height < b.position.y + b.size.height;
}); });
const CGFloat minDescender = descenderIt == stackedChildren.end() ? 0 : (*descenderIt).layoutableObject.layoutOptions.descender; const CGFloat minDescender = descenderIt == stackedChildren.end() ? 0 : (*descenderIt).layoutableObject.descender;
return {stackedChildren, crossSize, maxAscender, minDescender}; return {stackedChildren, crossSize, maxAscender, minDescender};
} }

View File

@@ -20,7 +20,7 @@ static CGFloat crossOffset(const ASStackLayoutSpecStyle &style,
const ASStackUnpositionedItem &l, const ASStackUnpositionedItem &l,
const CGFloat crossSize) const CGFloat crossSize)
{ {
switch (alignment(l.child.layoutOptions.alignSelf, style.alignItems)) { switch (alignment(l.child.alignSelf, style.alignItems)) {
case ASStackLayoutAlignItemsEnd: case ASStackLayoutAlignItemsEnd:
return crossSize - crossDimension(style.direction, l.layout.size); return crossSize - crossDimension(style.direction, l.layout.size);
case ASStackLayoutAlignItemsCenter: case ASStackLayoutAlignItemsCenter:
@@ -51,14 +51,14 @@ static ASStackPositionedLayout stackedLayout(const ASStackLayoutSpecStyle &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) -> ASLayout *{ auto stackedChildren = AS::map(unpositionedLayout.items, [&](const ASStackUnpositionedItem &l) -> ASLayout *{
p = p + directionPoint(style.direction, l.child.layoutOptions.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;
l.layout.position = p + directionPoint(style.direction, 0, crossOffset(style, l, crossSize)); l.layout.position = p + directionPoint(style.direction, 0, crossOffset(style, l, crossSize));
p = p + directionPoint(style.direction, stackDimension(style.direction, l.layout.size) + l.child.layoutOptions.spacingAfter, 0); p = p + directionPoint(style.direction, stackDimension(style.direction, l.layout.size) + l.child.spacingAfter, 0);
return l.layout; return l.layout;
}); });
return {stackedChildren, crossSize}; return {stackedChildren, crossSize};

View File

@@ -26,7 +26,7 @@ static ASLayout *crossChildLayout(const id<ASLayoutable> child,
const CGFloat crossMin, const CGFloat crossMin,
const CGFloat crossMax) const CGFloat crossMax)
{ {
const ASStackLayoutAlignItems alignItems = alignment(child.layoutOptions.alignSelf, style.alignItems); const ASStackLayoutAlignItems alignItems = alignment(child.alignSelf, style.alignItems);
// stretched children will have a cross dimension of at least crossMin // stretched children will have a cross dimension of at least crossMin
const CGFloat childCrossMin = alignItems == ASStackLayoutAlignItemsStretch ? crossMin : 0; const CGFloat childCrossMin = alignItems == ASStackLayoutAlignItemsStretch ? crossMin : 0;
const ASSizeRange childSizeRange = directionSizeRange(style.direction, stackMin, stackMax, childCrossMin, crossMax); const ASSizeRange childSizeRange = directionSizeRange(style.direction, stackMin, stackMax, childCrossMin, crossMax);
@@ -76,7 +76,7 @@ static void stretchChildrenAlongCrossDimension(std::vector<ASStackUnpositionedIt
const CGFloat childCrossMax = it == layouts.end() ? 0 : crossDimension(style.direction, it->layout.size); const CGFloat childCrossMax = it == layouts.end() ? 0 : crossDimension(style.direction, it->layout.size);
for (auto &l : layouts) { for (auto &l : layouts) {
const ASStackLayoutAlignItems alignItems = alignment(l.child.layoutOptions.alignSelf, style.alignItems); const ASStackLayoutAlignItems alignItems = alignment(l.child.alignSelf, style.alignItems);
const CGFloat cross = crossDimension(style.direction, l.layout.size); const CGFloat cross = crossDimension(style.direction, l.layout.size);
const CGFloat stack = stackDimension(style.direction, l.layout.size); const CGFloat stack = stackDimension(style.direction, l.layout.size);
@@ -112,7 +112,7 @@ static CGFloat computeStackDimensionSum(const std::vector<ASStackUnpositionedIte
// Start from default spacing between each child: // Start from default spacing between each child:
children.empty() ? 0 : style.spacing * (children.size() - 1), children.empty() ? 0 : style.spacing * (children.size() - 1),
[&](CGFloat x, const ASStackUnpositionedItem &l) { [&](CGFloat x, const ASStackUnpositionedItem &l) {
return x + l.child.layoutOptions.spacingBefore + l.child.layoutOptions.spacingAfter; return x + l.child.spacingBefore + l.child.spacingAfter;
}); });
// Sum up the childrens' dimensions (including spacing) in the stack direction. // Sum up the childrens' dimensions (including spacing) in the stack direction.
@@ -181,15 +181,15 @@ static std::function<BOOL(const ASStackUnpositionedItem &)> isFlexibleInViolatio
if (fabs(violation) < kViolationEpsilon) { if (fabs(violation) < kViolationEpsilon) {
return [](const ASStackUnpositionedItem &l) { return NO; }; return [](const ASStackUnpositionedItem &l) { return NO; };
} else if (violation > 0) { } else if (violation > 0) {
return [](const ASStackUnpositionedItem &l) { return l.child.layoutOptions.flexGrow; }; return [](const ASStackUnpositionedItem &l) { return l.child.flexGrow; };
} else { } else {
return [](const ASStackUnpositionedItem &l) { return l.child.layoutOptions.flexShrink; }; return [](const ASStackUnpositionedItem &l) { return l.child.flexShrink; };
} }
} }
ASDISPLAYNODE_INLINE BOOL isFlexibleInBothDirections(id<ASLayoutable> child) ASDISPLAYNODE_INLINE BOOL isFlexibleInBothDirections(id<ASLayoutable> child)
{ {
return child.layoutOptions.flexGrow && child.layoutOptions.flexShrink; return child.flexGrow && child.flexShrink;
} }
/** /**
@@ -294,8 +294,8 @@ static std::vector<ASStackUnpositionedItem> layoutChildrenAlongUnconstrainedStac
const CGFloat maxCrossDimension = crossDimension(style.direction, sizeRange.max); const CGFloat maxCrossDimension = crossDimension(style.direction, sizeRange.max);
return AS::map(children, [&](id<ASLayoutable> child) -> ASStackUnpositionedItem { return AS::map(children, [&](id<ASLayoutable> child) -> ASStackUnpositionedItem {
const BOOL isUnconstrainedFlexBasis = ASRelativeDimensionEqualToRelativeDimension(ASRelativeDimensionUnconstrained, child.layoutOptions.flexBasis); const BOOL isUnconstrainedFlexBasis = ASRelativeDimensionEqualToRelativeDimension(ASRelativeDimensionUnconstrained, child.flexBasis);
const CGFloat exactStackDimension = ASRelativeDimensionResolve(child.layoutOptions.flexBasis, stackDimension(style.direction, size)); const CGFloat exactStackDimension = ASRelativeDimensionResolve(child.flexBasis, stackDimension(style.direction, size));
if (useOptimizedFlexing && isFlexibleInBothDirections(child)) { if (useOptimizedFlexing && isFlexibleInBothDirections(child)) {
return { child, [ASLayout layoutWithLayoutableObject:child size:{0, 0}] }; return { child, [ASLayout layoutWithLayoutableObject:child size:{0, 0}] };

View File

@@ -95,7 +95,7 @@ static NSString *suffixForCenteringOptions(ASCenterLayoutSpecCenteringOptions ce
ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
foregroundNode.staticSize = {10, 10}; foregroundNode.staticSize = {10, 10};
foregroundNode.layoutOptions.flexGrow = YES; foregroundNode.flexGrow = YES;
ASCenterLayoutSpec *layoutSpec = ASCenterLayoutSpec *layoutSpec =
[ASCenterLayoutSpec [ASCenterLayoutSpec

View File

@@ -42,8 +42,8 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
]; ];
for (ASStaticSizeDisplayNode *subnode in subnodes) { for (ASStaticSizeDisplayNode *subnode in subnodes) {
subnode.staticSize = subnodeSize; subnode.staticSize = subnodeSize;
subnode.layoutOptions.flexGrow = flex; subnode.flexGrow = flex;
subnode.layoutOptions.flexShrink = flex; subnode.flexShrink = flex;
} }
return subnodes; return subnodes;
} }
@@ -115,7 +115,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO);
((ASDisplayNode *)subnodes[1]).layoutOptions.flexShrink = YES; ((ASDisplayNode *)subnodes[1]).flexShrink = YES;
// Width is 75px--that's less than the sum of the widths of the children, which is 100px. // Width is 75px--that's less than the sum of the widths of the children, which is 100px.
static ASSizeRange kSize = {{75, 0}, {75, 150}}; static ASSizeRange kSize = {{75, 0}, {75, 150}};
@@ -205,23 +205,23 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70};
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90};
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 10; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 10;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 20; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 20;
[self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingBefore"]; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingBefore"];
// Reset above spacing values // Reset above spacing values
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 0; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 0;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 0; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 0;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingAfter = 10; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingAfter = 10;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingAfter = 20; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingAfter = 20;
[self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingAfter"]; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingAfter"];
// Reset above spacing values // Reset above spacing values
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingAfter = 0; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingAfter = 0;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingAfter = 0; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingAfter = 0;
style.spacing = 10; style.spacing = 10;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = -10; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = -10;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingAfter = -10; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingAfter = -10;
[self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingBalancedOut"]; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingBalancedOut"];
} }
@@ -237,9 +237,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70};
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90};
((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30;
// width 0-300px; height 300px // width 0-300px; height 300px
static ASSizeRange kVariableHeight = {{0, 300}, {300, 300}}; static ASSizeRange kVariableHeight = {{0, 300}, {300, 300}};
@@ -255,9 +255,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
subnode2.staticSize = {50, 50}; subnode2.staticSize = {50, 50};
ASRatioLayoutSpec *child1 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.5 child:subnode1]; ASRatioLayoutSpec *child1 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.5 child:subnode1];
child1.layoutOptions.flexBasis = ASRelativeDimensionMakeWithPercent(1); child1.flexBasis = ASRelativeDimensionMakeWithPercent(1);
child1.layoutOptions.flexGrow = YES; child1.flexGrow = YES;
child1.layoutOptions.flexShrink = YES; child1.flexShrink = YES;
static ASSizeRange kFixedWidth = {{150, 0}, {150, INFINITY}}; static ASSizeRange kFixedWidth = {{150, 0}, {150, INFINITY}};
[self testStackLayoutSpecWithStyle:style children:@[child1, subnode2] sizeRange:kFixedWidth subnodes:@[subnode1, subnode2] identifier:nil]; [self testStackLayoutSpecWithStyle:style children:@[child1, subnode2] sizeRange:kFixedWidth subnodes:@[subnode1, subnode2] identifier:nil];
@@ -272,11 +272,11 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
ASStaticSizeDisplayNode *subnode1 = ASDisplayNodeWithBackgroundColor([UIColor redColor]); ASStaticSizeDisplayNode *subnode1 = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
subnode1.staticSize = {100, 100}; subnode1.staticSize = {100, 100};
subnode1.layoutOptions.flexShrink = YES; subnode1.flexShrink = YES;
ASStaticSizeDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); ASStaticSizeDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]);
subnode2.staticSize = {50, 50}; subnode2.staticSize = {50, 50};
subnode2.layoutOptions.flexShrink = YES; subnode2.flexShrink = YES;
NSArray *subnodes = @[subnode1, subnode2]; NSArray *subnodes = @[subnode1, subnode2];
static ASSizeRange kFixedWidth = {{150, 0}, {150, 100}}; static ASSizeRange kFixedWidth = {{150, 0}, {150, 100}};
@@ -292,7 +292,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
ASStaticSizeDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); ASStaticSizeDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]);
subnode2.staticSize = {50, 50}; subnode2.staticSize = {50, 50};
subnode2.layoutOptions.alignSelf = ASStackLayoutAlignSelfCenter; subnode2.alignSelf = ASStackLayoutAlignSelfCenter;
NSArray *subnodes = @[subnode1, subnode2]; NSArray *subnodes = @[subnode1, subnode2];
static ASSizeRange kFixedWidth = {{150, 0}, {150, INFINITY}}; static ASSizeRange kFixedWidth = {{150, 0}, {150, INFINITY}};
@@ -312,9 +312,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70};
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90};
((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30;
static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; static ASSizeRange kExactSize = {{300, 300}, {300, 300}};
[self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil];
@@ -333,9 +333,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70};
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90};
((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30;
static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; static ASSizeRange kExactSize = {{300, 300}, {300, 300}};
[self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil];
@@ -354,9 +354,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70};
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90};
((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30;
static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; static ASSizeRange kExactSize = {{300, 300}, {300, 300}};
[self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil];
@@ -375,9 +375,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70};
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90};
((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30;
static ASSizeRange kVariableSize = {{200, 200}, {300, 300}}; static ASSizeRange kVariableSize = {{200, 200}, {300, 300}};
// all children should be 200px wide // all children should be 200px wide
@@ -397,9 +397,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70};
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90};
((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0;
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20;
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30;
static ASSizeRange kVariableSize = {{50, 50}, {300, 300}}; static ASSizeRange kVariableSize = {{50, 50}, {300, 300}};
// all children should be 150px wide // all children should be 150px wide
@@ -420,8 +420,8 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {150, 150}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {150, 150};
for (ASStaticSizeDisplayNode *subnode in subnodes) { for (ASStaticSizeDisplayNode *subnode in subnodes) {
subnode.layoutOptions.flexGrow = YES; subnode.flexGrow = YES;
subnode.layoutOptions.flexBasis = ASRelativeDimensionMakeWithPoints(10); subnode.flexBasis = ASRelativeDimensionMakeWithPoints(10);
} }
// width 300px; height 0-150px. // width 300px; height 0-150px.
@@ -440,12 +440,12 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO);
for (ASStaticSizeDisplayNode *subnode in subnodes) { for (ASStaticSizeDisplayNode *subnode in subnodes) {
subnode.layoutOptions.flexGrow = YES; subnode.flexGrow = YES;
} }
// This should override the intrinsic size of 50pts and instead compute to 50% = 100pts. // This should override the intrinsic size of 50pts and instead compute to 50% = 100pts.
// The result should be that the red box is twice as wide as the blue and gree boxes after flexing. // The result should be that the red box is twice as wide as the blue and gree boxes after flexing.
((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.flexBasis = ASRelativeDimensionMakeWithPercent(0.5); ((ASStaticSizeDisplayNode *)subnodes[0]).flexBasis = ASRelativeDimensionMakeWithPercent(0.5);
static ASSizeRange kSize = {{200, 0}, {200, INFINITY}}; static ASSizeRange kSize = {{200, 0}, {200, INFINITY}};
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil]; [self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
@@ -461,7 +461,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {50, 50}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {50, 50};
for (ASStaticSizeDisplayNode *subnode in subnodes) { for (ASStaticSizeDisplayNode *subnode in subnodes) {
subnode.layoutOptions.flexBasis = ASRelativeDimensionMakeWithPoints(20); subnode.flexBasis = ASRelativeDimensionMakeWithPoints(20);
} }
static ASSizeRange kSize = {{300, 0}, {300, 150}}; static ASSizeRange kSize = {{300, 0}, {300, 150}};
@@ -479,8 +479,8 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {3000, 3000}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {3000, 3000};
ASRatioLayoutSpec *child2 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.0 child:subnodes[2]]; ASRatioLayoutSpec *child2 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.0 child:subnodes[2]];
child2.layoutOptions.flexGrow = YES; child2.flexGrow = YES;
child2.layoutOptions.flexShrink = YES; child2.flexShrink = YES;
// If cross axis stretching occurred *before* flexing, then the blue child would be stretched to 3000 points tall. // If cross axis stretching occurred *before* flexing, then the blue child would be stretched to 3000 points tall.
// Instead it should be stretched to 300 points tall, matching the red child and not overlapping the green inset. // Instead it should be stretched to 300 points tall, matching the red child and not overlapping the green inset.
@@ -505,13 +505,13 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
NSArray *subnodes = defaultSubnodes(); NSArray *subnodes = defaultSubnodes();
((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {300, 50}; ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {300, 50};
((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.flexShrink = YES; ((ASStaticSizeDisplayNode *)subnodes[0]).flexShrink = YES;
((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 50}; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 50};
((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.flexShrink = NO; ((ASStaticSizeDisplayNode *)subnodes[1]).flexShrink = NO;
((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {200, 50}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {200, 50};
((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.flexShrink = YES; ((ASStaticSizeDisplayNode *)subnodes[2]).flexShrink = YES;
// A width of 400px results in a violation of 200px. This is distributed equally among each flexible child, // A width of 400px results in a violation of 200px. This is distributed equally among each flexible child,
// causing both of them to be shrunk by 100px, resulting in widths of 300px, 100px, and 50px. // causing both of them to be shrunk by 100px, resulting in widths of 300px, 100px, and 50px.