diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 441430497b..ce6773d44b 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -233,12 +233,18 @@ 9C3061091B857EC400D0530B /* ASBaselineLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C3061051B857EC400D0530B /* ASBaselineLayoutSpec.mm */; }; 9C49C36F1B853957000B0DD5 /* ASStackLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C6BB3B21B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C6BB3B31B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C5FA3511B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C5FA3521B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C5FA3531B8F6ADF00A62714 /* ASLayoutOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.m */; }; 9C5FA3541B8F6ADF00A62714 /* ASLayoutOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.m */; }; + 9C5FA35D1B90C9A500A62714 /* ASLayoutOptionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA35B1B90C9A500A62714 /* ASLayoutOptionsPrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C5FA35E1B90C9A500A62714 /* ASLayoutOptionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA35B1B90C9A500A62714 /* ASLayoutOptionsPrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C5FA35F1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */; }; + 9C5FA3601B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */; }; + 9C5FA3631B91007100A62714 /* ASLayoutablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA3611B91007100A62714 /* ASLayoutablePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C5FA3641B91007100A62714 /* ASLayoutablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA3611B91007100A62714 /* ASLayoutablePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C6BB3B21B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C6BB3B31B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.m */; }; AC21EC101B3D0BF600C8B19A /* ASStackLayoutDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = AC21EC0F1B3D0BF600C8B19A /* ASStackLayoutDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; AC3C4A511A1139C100143C57 /* ASCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -475,7 +481,7 @@ 058D09DD195D050800B7D73C /* ASImageNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageNode.h; sourceTree = ""; }; 058D09DE195D050800B7D73C /* ASImageNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASImageNode.mm; sourceTree = ""; }; 058D09DF195D050800B7D73C /* ASTextNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTextNode.h; sourceTree = ""; }; - 058D09E0195D050800B7D73C /* ASTextNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASTextNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 058D09E0195D050800B7D73C /* ASTextNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASTextNode.mm; sourceTree = ""; }; 058D09E2195D050800B7D73C /* _ASDisplayLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASDisplayLayer.h; sourceTree = ""; }; 058D09E3195D050800B7D73C /* _ASDisplayLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _ASDisplayLayer.mm; sourceTree = ""; }; 058D09E4195D050800B7D73C /* _ASDisplayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASDisplayView.h; sourceTree = ""; }; @@ -586,9 +592,12 @@ 9C3061041B857EC400D0530B /* ASBaselineLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASBaselineLayoutSpec.h; path = AsyncDisplayKit/Layout/ASBaselineLayoutSpec.h; sourceTree = ""; }; 9C3061051B857EC400D0530B /* ASBaselineLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASBaselineLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASBaselineLayoutSpec.mm; sourceTree = ""; }; 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutable.h; path = AsyncDisplayKit/Layout/ASStackLayoutable.h; sourceTree = ""; }; - 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutable.h; path = AsyncDisplayKit/Layout/ASStaticLayoutable.h; sourceTree = ""; }; 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutOptions.h; path = AsyncDisplayKit/Layout/ASLayoutOptions.h; sourceTree = ""; }; 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASLayoutOptions.m; path = AsyncDisplayKit/Layout/ASLayoutOptions.m; sourceTree = ""; }; + 9C5FA35B1B90C9A500A62714 /* ASLayoutOptionsPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutOptionsPrivate.h; path = AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.h; sourceTree = ""; }; + 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASLayoutOptionsPrivate.mm; path = AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm; sourceTree = ""; }; + 9C5FA3611B91007100A62714 /* ASLayoutablePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutablePrivate.h; path = AsyncDisplayKit/Private/ASLayoutablePrivate.h; sourceTree = ""; }; + 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutable.h; path = AsyncDisplayKit/Layout/ASStaticLayoutable.h; sourceTree = ""; }; 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionViewTests.m; sourceTree = ""; }; AC21EC0F1B3D0BF600C8B19A /* ASStackLayoutDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutDefines.h; path = AsyncDisplayKit/Layout/ASStackLayoutDefines.h; sourceTree = ""; }; AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionView.h; sourceTree = ""; }; @@ -992,6 +1001,7 @@ ACF6ED0B1B17843500DA7C62 /* ASLayout.h */, ACF6ED0C1B17843500DA7C62 /* ASLayout.mm */, ACF6ED111B17843500DA7C62 /* ASLayoutable.h */, + 9C5FA3611B91007100A62714 /* ASLayoutablePrivate.h */, ACF6ED0D1B17843500DA7C62 /* ASLayoutSpec.h */, ACF6ED0E1B17843500DA7C62 /* ASLayoutSpec.mm */, ACF6ED121B17843500DA7C62 /* ASOverlayLayoutSpec.h */, @@ -1009,6 +1019,8 @@ 9C3061051B857EC400D0530B /* ASBaselineLayoutSpec.mm */, 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */, 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.m */, + 9C5FA35B1B90C9A500A62714 /* ASLayoutOptionsPrivate.h */, + 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */, ); name = Layout; path = ..; @@ -1085,6 +1097,7 @@ 058D0A4F195D05CB00B7D73C /* ASImageNode.h in Headers */, 058D0A50195D05CB00B7D73C /* ASImageNode.mm in Headers */, 058D0A51195D05CB00B7D73C /* ASTextNode.h in Headers */, + 9C5FA35D1B90C9A500A62714 /* ASLayoutOptionsPrivate.h in Headers */, 296A0A2E1A9516B2005ACEAA /* ASBatchFetching.h in Headers */, 058D0A52195D05CB00B7D73C /* ASTextNode.mm in Headers */, 055F1A3819ABD413004DAFF1 /* ASRangeController.h in Headers */, @@ -1127,6 +1140,7 @@ 18C2ED7E1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */, 058D0A6C195D05EC00B7D73C /* _ASAsyncTransactionContainer.m in Headers */, 6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */, + 9C5FA3631B91007100A62714 /* ASLayoutablePrivate.h in Headers */, 058D0A6D195D05EC00B7D73C /* _ASAsyncTransactionGroup.h in Headers */, 058D0A6E195D05EC00B7D73C /* _ASAsyncTransactionGroup.m in Headers */, 205F0E1D1B373A2C007741D0 /* ASCollectionViewLayoutController.h in Headers */, @@ -1179,6 +1193,7 @@ B35062321B010EFD0018CF92 /* ASTextNodeShadower.h in Headers */, 34EFC7651B701CCC00AD841F /* ASRelativeSize.h in Headers */, B35062431B010EFD0018CF92 /* UIView+ASConvenience.h in Headers */, + 9C5FA35E1B90C9A500A62714 /* ASLayoutOptionsPrivate.h in Headers */, B31A241E1B0114FD0016AE7A /* AsyncDisplayKit.h in Headers */, B350622D1B010EFD0018CF92 /* ASScrollDirection.h in Headers */, B35061FB1B010EFD0018CF92 /* ASDisplayNode.h in Headers */, @@ -1267,6 +1282,7 @@ B35062591B010F070018CF92 /* ASBaseDefines.h in Headers */, B35062191B010EFD0018CF92 /* ASDealloc2MainObject.h in Headers */, B350620F1B010EFD0018CF92 /* _ASDisplayLayer.h in Headers */, + 9C5FA3641B91007100A62714 /* ASLayoutablePrivate.h in Headers */, B35062531B010EFD0018CF92 /* ASImageNode+CGExtras.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1472,6 +1488,7 @@ 058D0A18195D050800B7D73C /* _ASDisplayLayer.mm in Sources */, ACF6ED321B17843500DA7C62 /* ASStaticLayoutSpec.mm in Sources */, 9C5FA3531B8F6ADF00A62714 /* ASLayoutOptions.m in Sources */, + 9C5FA35F1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */, ACF6ED2C1B17843500DA7C62 /* ASOverlayLayoutSpec.mm in Sources */, 058D0A2C195D050800B7D73C /* ASSentinel.m in Sources */, 205F0E221B376416007741D0 /* CGRect+ASConvenience.m in Sources */, @@ -1584,6 +1601,7 @@ B35062471B010EFD0018CF92 /* ASBatchFetching.m in Sources */, B350624E1B010EFD0018CF92 /* ASDisplayNode+AsyncDisplay.mm in Sources */, 34EFC76F1B701CF700AD841F /* ASRatioLayoutSpec.mm in Sources */, + 9C5FA3601B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */, 34EFC7681B701CDE00AD841F /* ASLayout.mm in Sources */, B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */, 34EFC75C1B701BD200AD841F /* ASDimension.mm in Sources */, diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 4b5419cc40..54a2d94b1e 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -9,6 +9,7 @@ #import "ASDisplayNode.h" #import "ASDisplayNode+Subclasses.h" #import "ASDisplayNodeInternal.h" +#import "ASLayoutOptionsPrivate.h" #import @@ -41,6 +42,7 @@ @implementation ASDisplayNode +@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions; @synthesize preferredFrameSize = _preferredFrameSize; BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector) @@ -670,11 +672,6 @@ static inline BOOL _ASDisplayNodeIsAncestorOfDisplayNode(ASDisplayNode *possible return NO; } -- (id)finalLayoutable -{ - return self; -} - /** * NOTE: It is an error to try to convert between nodes which do not share a common ancestor. This behavior is * disallowed in UIKit documentation and the behavior is left undefined. The output does not have a rigorously defined @@ -1852,6 +1849,10 @@ static void _recursivelySetDisplaySuspended(ASDisplayNode *node, CALayer *layer, return !self.layerBacked && [self.view canPerformAction:action withSender:sender]; } +- (id)finalLayoutable { + return self; +} + @end @implementation ASDisplayNode (Debugging) diff --git a/AsyncDisplayKit/Layout/ASLayoutOptions.h b/AsyncDisplayKit/Layout/ASLayoutOptions.h index 0bdee1ad09..091f078ae9 100644 --- a/AsyncDisplayKit/Layout/ASLayoutOptions.h +++ b/AsyncDisplayKit/Layout/ASLayoutOptions.h @@ -16,6 +16,9 @@ @interface ASLayoutOptions : NSObject ++ (void)setDefaultLayoutOptionsClass:(Class)defaultLayoutOptionsClass; ++ (Class)defaultLayoutOptionsClass; + - (instancetype)initWithLayoutable:(id)layoutable; - (void)setValuesFromLayoutable:(id)layoutable; @@ -42,7 +45,7 @@ #pragma mark - ASStaticLayoutable @property (nonatomic, readwrite) ASRelativeSizeRange sizeRange; -@property (nonatomic, readwrite) CGPoint position; +@property (nonatomic, readwrite) CGPoint layoutPosition; - (void)setupDefaults; diff --git a/AsyncDisplayKit/Layout/ASLayoutOptions.m b/AsyncDisplayKit/Layout/ASLayoutOptions.m index 6207ef0d07..df3fc0fb61 100644 --- a/AsyncDisplayKit/Layout/ASLayoutOptions.m +++ b/AsyncDisplayKit/Layout/ASLayoutOptions.m @@ -15,6 +15,18 @@ @implementation ASLayoutOptions +static Class gDefaultLayoutOptionsClass = nil; ++ (void)setDefaultLayoutOptionsClass:(Class)defaultLayoutOptionsClass +{ + gDefaultLayoutOptionsClass = defaultLayoutOptionsClass; +} + ++ (Class)defaultLayoutOptionsClass +{ + return gDefaultLayoutOptionsClass; +} + + - (instancetype)initWithLayoutable:(id)layoutable; { self = [super init]; @@ -79,7 +91,7 @@ copy.descender = self.descender; copy.sizeRange = self.sizeRange; - copy.position = self.position; + copy.layoutPosition = self.layoutPosition; return copy; } @@ -98,7 +110,7 @@ _descender = 0; _sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero)); - _position = CGPointZero; + _layoutPosition = CGPointZero; } // Do this here instead of in Node/Spec subclasses so that custom specs can set default values @@ -112,7 +124,7 @@ if ([layoutable isKindOfClass:[ASDisplayNode class]]) { ASDisplayNode *displayNode = (ASDisplayNode *)layoutable; self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize)); - self.position = displayNode.frame.origin; + self.layoutPosition = displayNode.frame.origin; } } diff --git a/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.h b/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.h new file mode 100644 index 0000000000..f7b7f9b9fc --- /dev/null +++ b/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.h @@ -0,0 +1,30 @@ +// +// ASDisplayNode+Layoutable.h +// AsyncDisplayKit +// +// Created by Ricky Cancro on 8/28/15. +// Copyright (c) 2015 Facebook. All rights reserved. +// + +#import +#import + + +@interface ASDisplayNode() +{ + ASLayoutOptions *_layoutOptions; +} +@end + +@interface ASDisplayNode(ASLayoutOptions) +@end + +@interface ASLayoutSpec() +{ + ASLayoutOptions *_layoutOptions; +} +@end + +@interface ASLayoutSpec(ASLayoutOptions) +@end + diff --git a/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm b/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm new file mode 100644 index 0000000000..b0332a8007 --- /dev/null +++ b/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm @@ -0,0 +1,129 @@ +// +// ASDisplayNode+Layoutable.m +// AsyncDisplayKit +// +// Created by Ricky Cancro on 8/28/15. +// Copyright (c) 2015 Facebook. All rights reserved. +// + +#import "ASLayoutOptionsPrivate.h" +#import + + +#define ASLayoutOptionsForwarding \ +- (ASLayoutOptions *)layoutOptions\ +{\ +if (_layoutOptions == nil) {\ +_layoutOptions = [[[ASLayoutOptions defaultLayoutOptionsClass] alloc] init];\ +}\ +return _layoutOptions;\ +}\ +\ +- (CGFloat)spacingBefore\ +{\ +return self.layoutOptions.spacingBefore;\ +}\ +\ +- (void)setSpacingBefore:(CGFloat)spacingBefore\ +{\ +self.layoutOptions.spacingBefore = spacingBefore;\ +}\ +\ +- (CGFloat)spacingAfter\ +{\ +return self.layoutOptions.spacingAfter;\ +}\ +\ +- (void)setSpacingAfter:(CGFloat)spacingAfter\ +{\ +self.layoutOptions.spacingAfter = spacingAfter;\ +}\ +\ +- (BOOL)flexGrow\ +{\ +return self.layoutOptions.flexGrow;\ +}\ +\ +- (void)setFlexGrow:(BOOL)flexGrow\ +{\ +self.layoutOptions.flexGrow = flexGrow;\ +}\ +\ +- (BOOL)flexShrink\ +{\ +return self.layoutOptions.flexShrink;\ +}\ +\ +- (void)setFlexShrink:(BOOL)flexShrink\ +{\ +self.layoutOptions.flexShrink = flexShrink;\ +}\ +\ +- (ASRelativeDimension)flexBasis\ +{\ +return self.layoutOptions.flexBasis;\ +}\ +\ +- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ +{\ +self.layoutOptions.flexBasis = flexBasis;\ +}\ +\ +- (ASStackLayoutAlignSelf)alignSelf\ +{\ +return self.layoutOptions.alignSelf;\ +}\ +\ +- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ +{\ + self.layoutOptions.alignSelf = alignSelf;\ +}\ +\ +- (CGFloat)ascender\ +{\ + return self.layoutOptions.ascender;\ +}\ +\ +- (void)setAscender:(CGFloat)ascender\ +{\ + self.layoutOptions.ascender = ascender;\ +}\ +\ +- (CGFloat)descender\ +{\ + return self.layoutOptions.descender;\ +}\ +\ +- (void)setDescender:(CGFloat)descender\ +{\ + self.layoutOptions.descender = descender;\ +}\ +\ +- (ASRelativeSizeRange)sizeRange\ +{\ + return self.layoutOptions.sizeRange;\ +}\ +\ +- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ +{\ + self.layoutOptions.sizeRange = sizeRange;\ +}\ +\ +- (CGPoint)layoutPosition\ +{\ + return self.layoutOptions.layoutPosition;\ +}\ +\ +- (void)setLayoutPosition:(CGPoint)position\ +{\ + self.layoutOptions.layoutPosition = position;\ +}\ + + +@implementation ASDisplayNode(ASLayoutOptions) +ASLayoutOptionsForwarding +@end + +@implementation ASLayoutSpec(ASLayoutOptions) +ASLayoutOptionsForwarding +@end diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.h b/AsyncDisplayKit/Layout/ASLayoutSpec.h index dc4f100bb5..494d5d1198 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.h @@ -30,8 +30,8 @@ - (id)childForIdentifier:(NSString *)identifier; - (NSArray *)children; -+ (ASLayoutOptions *)layoutOptionsForChild:(id)child; -+ (void)associateLayoutOptions:(ASLayoutOptions *)layoutOptions withChild:(id)child; -+ (void)setLayoutOptionsClass:(Class)layoutOptionsClass; +//+ (ASLayoutOptions *)layoutOptionsForChild:(id)child; +//+ (void)associateLayoutOptions:(ASLayoutOptions *)layoutOptions withChild:(id)child; +//+ (void)setLayoutOptionsClass:(Class)layoutOptionsClass; @end diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index f277a01bc4..994ad8428e 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -15,6 +15,8 @@ #import "ASInternalHelpers.h" #import "ASLayout.h" +#import "ASLayoutOptions.h" +#import "ASLayoutOptionsPrivate.h" #import @@ -27,6 +29,7 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; @implementation ASLayoutSpec +@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions; @synthesize layoutChildren = _layoutChildren; - (instancetype)init @@ -71,16 +74,20 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; NSMutableArray *finalChildren = [NSMutableArray arrayWithCapacity:children.count]; for (id child in children) { ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:child]; - id finalLayoutable = [child finalLayoutable]; - layoutOptions.isMutable = NO; - - if (finalLayoutable != child) { - ASLayoutOptions *finalLayoutOptions = [layoutOptions copy]; - finalLayoutOptions.isMutable = NO; - [ASLayoutSpec associateLayoutOptions:finalLayoutOptions withChild:finalLayoutable]; + if ([child respondsToSelector:@selector(finalLayoutable)]) { + id finalLayoutable = [child performSelector:@selector(finalLayoutable)]; + layoutOptions.isMutable = NO; + + if (finalLayoutable != child) { + ASLayoutOptions *finalLayoutOptions = [layoutOptions copy]; + finalLayoutOptions.isMutable = NO; + [ASLayoutSpec associateLayoutOptions:finalLayoutOptions withChild:finalLayoutable]; + [finalChildren addObject:finalLayoutable]; + } + } else { + [finalChildren addObject:child]; } - [finalChildren addObject:finalLayoutable]; } self.layoutChildren[kDefaultChildrenKey] = [NSArray arrayWithArray:finalChildren]; diff --git a/AsyncDisplayKit/Layout/ASLayoutable.h b/AsyncDisplayKit/Layout/ASLayoutable.h index 8ba86fdc1b..2ea76f3983 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.h +++ b/AsyncDisplayKit/Layout/ASLayoutable.h @@ -9,8 +9,10 @@ */ #import +#import #import -#import + +#import @class ASLayout; @class ASLayoutSpec; @@ -20,7 +22,7 @@ * so that instances of that class can be used to build layout trees. The protocol also provides information * about how an object should be laid out within an ASStackLayoutSpec. */ -@protocol ASLayoutable +@protocol ASLayoutable /** * @abstract Calculate a layout based on given size range. @@ -31,16 +33,17 @@ */ - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize; -/** - @abstract Give this object a last chance to add itself to a container ASLayoutable (most likely an ASLayoutSpec) before - being added to a ASLayoutSpec. - - For example, consider a node whose superclass is laid out via calculateLayoutThatFits:. The subclass cannot implement - layoutSpecThatFits: since its ASLayout is already being created by calculateLayoutThatFits:. By implementing this method - a subclass can wrap itself in an ASLayoutSpec right before it is added to a layout spec. - - It is rare that a class will need to implement this method. - */ -- (id)finalLayoutable; +@property (nonatomic, readwrite) CGFloat spacingBefore; +@property (nonatomic, readwrite) CGFloat spacingAfter; +@property (nonatomic, readwrite) BOOL flexGrow; +@property (nonatomic, readwrite) BOOL flexShrink; +@property (nonatomic, readwrite) ASRelativeDimension flexBasis; +@property (nonatomic, readwrite) ASStackLayoutAlignSelf alignSelf; + +@property (nonatomic, readwrite) CGFloat ascender; +@property (nonatomic, readwrite) CGFloat descender; + +@property (nonatomic, readwrite) ASRelativeSizeRange sizeRange; +@property (nonatomic, readwrite) CGPoint layoutPosition; @end diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm index b458207b8e..e9f47c2ecd 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm @@ -11,6 +11,8 @@ #import "ASStaticLayoutSpec.h" #import "ASLayoutSpecUtilities.h" +#import "ASLayoutOptions.h" +#import "ASLayoutOptionsPrivate.h" #import "ASInternalHelpers.h" #import "ASLayout.h" #import "ASStaticLayoutable.h" @@ -45,16 +47,16 @@ NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:self.children.count]; for (id child in self.children) { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:child]; + ASLayoutOptions *layoutOptions = child.layoutOptions; CGSize autoMaxSize = { - constrainedSize.max.width - layoutOptions.position.x, - constrainedSize.max.height - layoutOptions.position.y + constrainedSize.max.width - layoutOptions.layoutPosition.x, + constrainedSize.max.height - layoutOptions.layoutPosition.y }; ASSizeRange childConstraint = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, layoutOptions.sizeRange) ? ASSizeRangeMake({0, 0}, autoMaxSize) : ASRelativeSizeRangeResolve(layoutOptions.sizeRange, size); ASLayout *sublayout = [child measureWithSizeRange:childConstraint]; - sublayout.position = layoutOptions.position; + sublayout.position = layoutOptions.layoutPosition; [sublayouts addObject:sublayout]; } diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutable.h b/AsyncDisplayKit/Layout/ASStaticLayoutable.h index 8e7d74acf3..f2e565a7a9 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutable.h +++ b/AsyncDisplayKit/Layout/ASStaticLayoutable.h @@ -18,6 +18,6 @@ @property (nonatomic, assign) ASRelativeSizeRange sizeRange; /** The position of this object within its parent spec. */ -@property (nonatomic, assign) CGPoint position; +@property (nonatomic, assign) CGPoint layoutPosition; @end diff --git a/AsyncDisplayKit/Private/ASBaselinePositionedLayout.mm b/AsyncDisplayKit/Private/ASBaselinePositionedLayout.mm index bf0239c952..bf01ff179e 100644 --- a/AsyncDisplayKit/Private/ASBaselinePositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASBaselinePositionedLayout.mm @@ -12,17 +12,19 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" +#import "ASLayoutOptions.h" static CGFloat baselineForItem(const ASBaselineLayoutSpecStyle &style, const ASLayout *layout) { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:layout.layoutableObject]; + + __weak id child = layout.layoutableObject; switch (style.baselineAlignment) { case ASBaselineLayoutBaselineAlignmentNone: return 0; case ASBaselineLayoutBaselineAlignmentFirst: - return layoutOptions.ascender; + return child.layoutOptions.ascender; case ASBaselineLayoutBaselineAlignmentLast: - return layout.size.height + layoutOptions.descender; + return layout.size.height + child.layoutOptions.descender; } } @@ -33,10 +35,10 @@ static CGFloat baselineOffset(const ASBaselineLayoutSpecStyle &style, const CGFloat maxBaseline) { if (style.stackLayoutStyle.direction == ASStackLayoutDirectionHorizontal) { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:l.layoutableObject]; + __weak id child = l.layoutableObject; switch (style.baselineAlignment) { case ASBaselineLayoutBaselineAlignmentFirst: - return maxAscender - layoutOptions.ascender; + return maxAscender - child.layoutOptions.ascender; case ASBaselineLayoutBaselineAlignmentLast: return maxBaseline - baselineForItem(style, l); case ASBaselineLayoutBaselineAlignmentNone: @@ -90,11 +92,9 @@ ASBaselinePositionedLayout ASBaselinePositionedLayout::compute(const ASStackPosi 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){ - ASLayoutOptions *layoutOptionsA = [ASLayoutSpec layoutOptionsForChild:a.layoutableObject]; - ASLayoutOptions *layoutOptionsB = [ASLayoutSpec layoutOptionsForChild:b.layoutableObject]; - return layoutOptionsA.ascender < layoutOptionsB.ascender; + return a.layoutableObject.layoutOptions.ascender < b.layoutableObject.layoutOptions.ascender; }); - const CGFloat maxAscender = baselineIt == positionedLayout.sublayouts.end() ? 0 : [ASLayoutSpec layoutOptionsForChild:(*ascenderIt).layoutableObject].ascender; + const CGFloat maxAscender = baselineIt == positionedLayout.sublayouts.end() ? 0 : (*ascenderIt).layoutableObject.layoutOptions.ascender; /* Step 3: Take each child and update its layout position based on the baseline offset. @@ -107,8 +107,8 @@ ASBaselinePositionedLayout ASBaselinePositionedLayout::compute(const ASStackPosi CGPoint p = CGPointZero; BOOL first = YES; auto stackedChildren = AS::map(positionedLayout.sublayouts, [&](ASLayout *l) -> ASLayout *{ - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:l.layoutableObject]; - p = p + directionPoint(stackStyle.direction, layoutOptions.spacingBefore, 0); + __weak id child = l.layoutableObject; + p = p + directionPoint(stackStyle.direction, child.layoutOptions.spacingBefore, 0); if (first) { // if this is the first item use the previously computed start point p = l.position; @@ -125,9 +125,9 @@ ASBaselinePositionedLayout ASBaselinePositionedLayout::compute(const ASStackPosi // node from baselines and not bounding boxes. CGFloat spacingAfterBaseline = 0; if (stackStyle.direction == ASStackLayoutDirectionVertical) { - spacingAfterBaseline = layoutOptions.descender; + spacingAfterBaseline = child.layoutOptions.descender; } - p = p + directionPoint(stackStyle.direction, stackDimension(stackStyle.direction, l.size) + layoutOptions.spacingAfter + spacingAfterBaseline, 0); + p = p + directionPoint(stackStyle.direction, stackDimension(stackStyle.direction, l.size) + child.layoutOptions.spacingAfter + spacingAfterBaseline, 0); return l; }); @@ -157,7 +157,7 @@ ASBaselinePositionedLayout ASBaselinePositionedLayout::compute(const ASStackPosi 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; }); - const CGFloat minDescender = descenderIt == stackedChildren.end() ? 0 : [ASLayoutSpec layoutOptionsForChild:(*descenderIt).layoutableObject].descender; + const CGFloat minDescender = descenderIt == stackedChildren.end() ? 0 : (*descenderIt).layoutableObject.layoutOptions.descender; return {stackedChildren, crossSize, maxAscender, minDescender}; } diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index 5a8883ed02..d727bc5bab 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -17,6 +17,7 @@ #import "ASDisplayNode.h" #import "ASSentinel.h" #import "ASThread.h" +#import "ASLayoutOptions.h" BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector); void ASDisplayNodePerformBlockOnMainThread(void (^block)()); @@ -71,7 +72,7 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) { NSMutableSet *_pendingDisplayNodes; _ASPendingState *_pendingViewState; - + struct { // public properties unsigned synchronous:1; @@ -153,6 +154,8 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) { @property (nonatomic, assign) CGFloat contentsScaleForDisplay; +- (id)finalLayoutable; + @end @interface UIView (ASDisplayNodeInternal) diff --git a/AsyncDisplayKit/Private/ASLayoutablePrivate.h b/AsyncDisplayKit/Private/ASLayoutablePrivate.h new file mode 100644 index 0000000000..360c91570b --- /dev/null +++ b/AsyncDisplayKit/Private/ASLayoutablePrivate.h @@ -0,0 +1,16 @@ +// +// ASLayoutablePrivate.h +// AsyncDisplayKit +// +// Created by Ricky Cancro on 8/28/15. +// Copyright (c) 2015 Facebook. All rights reserved. +// +#import + +@class ASLayoutSpec; +@class ASLayoutOptions; + +@protocol ASLayoutablePrivate +- (ASLayoutSpec *)finalLayoutable; +@property (nonatomic, strong, readonly) ASLayoutOptions *layoutOptions; +@end diff --git a/AsyncDisplayKit/Private/ASStackPositionedLayout.mm b/AsyncDisplayKit/Private/ASStackPositionedLayout.mm index 31ff00b595..95b445043c 100644 --- a/AsyncDisplayKit/Private/ASStackPositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackPositionedLayout.mm @@ -14,13 +14,13 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" #import "ASLayoutable.h" +#import "ASLayoutOptions.h" static CGFloat crossOffset(const ASStackLayoutSpecStyle &style, const ASStackUnpositionedItem &l, const CGFloat crossSize) { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:l.child]; - switch (alignment(layoutOptions.alignSelf, style.alignItems)) { + switch (alignment(l.child.layoutOptions.alignSelf, style.alignItems)) { case ASStackLayoutAlignItemsEnd: return crossSize - crossDimension(style.direction, l.layout.size); case ASStackLayoutAlignItemsCenter: @@ -49,15 +49,14 @@ static ASStackPositionedLayout stackedLayout(const ASStackLayoutSpecStyle &style CGPoint p = directionPoint(style.direction, offset, 0); BOOL first = YES; auto stackedChildren = AS::map(unpositionedLayout.items, [&](const ASStackUnpositionedItem &l) -> ASLayout *{ - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:l.child]; - p = p + directionPoint(style.direction, layoutOptions.spacingBefore, 0); + p = p + directionPoint(style.direction, l.child.layoutOptions.spacingBefore, 0); if (!first) { p = p + directionPoint(style.direction, style.spacing, 0); } first = NO; l.layout.position = p + directionPoint(style.direction, 0, crossOffset(style, l, crossSize)); - p = p + directionPoint(style.direction, stackDimension(style.direction, l.layout.size) + layoutOptions.spacingAfter, 0); + p = p + directionPoint(style.direction, stackDimension(style.direction, l.layout.size) + l.child.layoutOptions.spacingAfter, 0); return l.layout; }); return {stackedChildren, crossSize}; diff --git a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm index da4000cd5e..7514507a01 100644 --- a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm @@ -14,6 +14,7 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" +#import "ASLayoutOptions.h" /** Sizes the child given the parameters specified, and returns the computed layout. @@ -25,8 +26,7 @@ static ASLayout *crossChildLayout(const id child, const CGFloat crossMin, const CGFloat crossMax) { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:child]; - const ASStackLayoutAlignItems alignItems = alignment(layoutOptions.alignSelf, style.alignItems); + const ASStackLayoutAlignItems alignItems = alignment(child.layoutOptions.alignSelf, style.alignItems); // stretched children will have a cross dimension of at least crossMin const CGFloat childCrossMin = alignItems == ASStackLayoutAlignItemsStretch ? crossMin : 0; const ASSizeRange childSizeRange = directionSizeRange(style.direction, stackMin, stackMax, childCrossMin, crossMax); @@ -76,8 +76,7 @@ static void stretchChildrenAlongCrossDimension(std::vectorlayout.size); for (auto &l : layouts) { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:l.child]; - const ASStackLayoutAlignItems alignItems = alignment(layoutOptions.alignSelf, style.alignItems); + const ASStackLayoutAlignItems alignItems = alignment(l.child.layoutOptions.alignSelf, style.alignItems); const CGFloat cross = crossDimension(style.direction, l.layout.size); const CGFloat stack = stackDimension(style.direction, l.layout.size); @@ -113,8 +112,7 @@ static CGFloat computeStackDimensionSum(const std::vector isFlexibleInViolatio if (fabs(violation) < kViolationEpsilon) { return [](const ASStackUnpositionedItem &l) { return NO; }; } else if (violation > 0) { - return [](const ASStackUnpositionedItem &l) { return [ASLayoutSpec layoutOptionsForChild:l.child].flexGrow; }; + return [](const ASStackUnpositionedItem &l) { return l.child.layoutOptions.flexGrow; }; } else { - return [](const ASStackUnpositionedItem &l) { return [ASLayoutSpec layoutOptionsForChild:l.child].flexShrink; }; + return [](const ASStackUnpositionedItem &l) { return l.child.layoutOptions.flexShrink; }; } } ASDISPLAYNODE_INLINE BOOL isFlexibleInBothDirections(id child) { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:child]; - return layoutOptions.flexGrow && layoutOptions.flexShrink; + return child.layoutOptions.flexGrow && child.layoutOptions.flexShrink; } /** @@ -297,9 +294,8 @@ static std::vector layoutChildrenAlongUnconstrainedStac const CGFloat maxCrossDimension = crossDimension(style.direction, sizeRange.max); return AS::map(children, [&](id child) -> ASStackUnpositionedItem { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:child]; - const BOOL isUnconstrainedFlexBasis = ASRelativeDimensionEqualToRelativeDimension(ASRelativeDimensionUnconstrained, layoutOptions.flexBasis); - const CGFloat exactStackDimension = ASRelativeDimensionResolve(layoutOptions.flexBasis, stackDimension(style.direction, size)); + const BOOL isUnconstrainedFlexBasis = ASRelativeDimensionEqualToRelativeDimension(ASRelativeDimensionUnconstrained, child.layoutOptions.flexBasis); + const CGFloat exactStackDimension = ASRelativeDimensionResolve(child.layoutOptions.flexBasis, stackDimension(style.direction, size)); if (useOptimizedFlexing && isFlexibleInBothDirections(child)) { return { child, [ASLayout layoutWithLayoutableObject:child size:{0, 0}] }; diff --git a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm index 6ea803ba93..45e167afd7 100644 --- a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm @@ -13,6 +13,7 @@ #import "ASBackgroundLayoutSpec.h" #import "ASCenterLayoutSpec.h" #import "ASStackLayoutSpec.h" +#import "ASLayoutOptions.h" static const ASSizeRange kSize = {{100, 120}, {320, 160}}; @@ -94,7 +95,7 @@ static NSString *suffixForCenteringOptions(ASCenterLayoutSpecCenteringOptions ce ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); foregroundNode.staticSize = {10, 10}; - [ASLayoutSpec layoutOptionsForChild:foregroundNode].flexGrow = YES; + foregroundNode.layoutOptions.flexGrow = YES; ASCenterLayoutSpec *layoutSpec = [ASCenterLayoutSpec diff --git a/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm index 2e9c2e7802..fbd893940b 100644 --- a/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm @@ -15,6 +15,7 @@ #import "ASBackgroundLayoutSpec.h" #import "ASRatioLayoutSpec.h" #import "ASInsetLayoutSpec.h" +#import "ASLayoutOptions.h" @interface ASStackLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase @end @@ -41,8 +42,8 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ]; for (ASStaticSizeDisplayNode *subnode in subnodes) { subnode.staticSize = subnodeSize; - [ASLayoutSpec layoutOptionsForChild:subnode].flexGrow = flex; - [ASLayoutSpec layoutOptionsForChild:subnode].flexShrink = flex; + subnode.layoutOptions.flexGrow = flex; + subnode.layoutOptions.flexShrink = flex; } return subnodes; } @@ -114,7 +115,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); - [ASLayoutSpec layoutOptionsForChild:((ASDisplayNode *)subnodes[1])].flexShrink = YES; + ((ASDisplayNode *)subnodes[1]).layoutOptions.flexShrink = YES; // 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}}; @@ -204,25 +205,23 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - ASLayoutOptions *layoutOptions1 = [ASLayoutSpec layoutOptionsForChild:subnodes[1]]; - ASLayoutOptions *layoutOptions2 = [ASLayoutSpec layoutOptionsForChild:subnodes[2]]; - layoutOptions1.spacingBefore = 10; - layoutOptions2.spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 10; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 20; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingBefore"]; // Reset above spacing values - layoutOptions1.spacingBefore = 0; - layoutOptions2.spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 0; - layoutOptions1.spacingAfter = 10; - layoutOptions2.spacingAfter = 20; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingAfter = 10; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingAfter = 20; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingAfter"]; // Reset above spacing values - layoutOptions1.spacingAfter = 0; - layoutOptions2.spacingAfter = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingAfter = 0; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingAfter = 0; style.spacing = 10; - layoutOptions1.spacingBefore = -10; - layoutOptions2.spacingAfter = -10; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = -10; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingAfter = -10; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingBalancedOut"]; } @@ -238,9 +237,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[0])].spacingBefore = 0; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[1])].spacingBefore = 20; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[2])].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; // width 0-300px; height 300px static ASSizeRange kVariableHeight = {{0, 300}, {300, 300}}; @@ -256,10 +255,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) subnode2.staticSize = {50, 50}; ASRatioLayoutSpec *child1 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.5 child:subnode1]; - ASLayoutOptions *layoutOptions1 = [ASLayoutSpec layoutOptionsForChild:child1]; - layoutOptions1.flexBasis = ASRelativeDimensionMakeWithPercent(1); - layoutOptions1.flexGrow = YES; - layoutOptions1.flexShrink = YES; + child1.layoutOptions.flexBasis = ASRelativeDimensionMakeWithPercent(1); + child1.layoutOptions.flexGrow = YES; + child1.layoutOptions.flexShrink = YES; static ASSizeRange kFixedWidth = {{150, 0}, {150, INFINITY}}; [self testStackLayoutSpecWithStyle:style children:@[child1, subnode2] sizeRange:kFixedWidth subnodes:@[subnode1, subnode2] identifier:nil]; @@ -274,11 +272,11 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ASStaticSizeDisplayNode *subnode1 = ASDisplayNodeWithBackgroundColor([UIColor redColor]); subnode1.staticSize = {100, 100}; - [ASLayoutSpec layoutOptionsForChild:subnode1].flexShrink = YES; + subnode1.layoutOptions.flexShrink = YES; ASStaticSizeDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); subnode2.staticSize = {50, 50}; - [ASLayoutSpec layoutOptionsForChild:subnode2].flexShrink = YES; + subnode2.layoutOptions.flexShrink = YES; NSArray *subnodes = @[subnode1, subnode2]; static ASSizeRange kFixedWidth = {{150, 0}, {150, 100}}; @@ -294,7 +292,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ASStaticSizeDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); subnode2.staticSize = {50, 50}; - [ASLayoutSpec layoutOptionsForChild:subnode2].alignSelf = ASStackLayoutAlignSelfCenter; + subnode2.layoutOptions.alignSelf = ASStackLayoutAlignSelfCenter; NSArray *subnodes = @[subnode1, subnode2]; static ASSizeRange kFixedWidth = {{150, 0}, {150, INFINITY}}; @@ -314,9 +312,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[0])].spacingBefore = 0; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[1])].spacingBefore = 20; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[2])].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; @@ -335,9 +333,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[0])].spacingBefore = 0; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[1])].spacingBefore = 20; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[2])].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; @@ -356,9 +354,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[0])].spacingBefore = 0; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[1])].spacingBefore = 20; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[2])].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; @@ -377,9 +375,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[0])].spacingBefore = 0; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[1])].spacingBefore = 20; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[2])].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; static ASSizeRange kVariableSize = {{200, 200}, {300, 300}}; // all children should be 200px wide @@ -399,9 +397,9 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[0])].spacingBefore = 0; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[1])].spacingBefore = 20; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[2])].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.spacingBefore = 30; static ASSizeRange kVariableSize = {{50, 50}, {300, 300}}; // all children should be 150px wide @@ -422,9 +420,8 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {150, 150}; for (ASStaticSizeDisplayNode *subnode in subnodes) { - ASLayoutOptions *layoutOptions = [ASLayoutSpec layoutOptionsForChild:subnode]; - layoutOptions.flexGrow = YES; - layoutOptions.flexBasis = ASRelativeDimensionMakeWithPoints(10); + subnode.layoutOptions.flexGrow = YES; + subnode.layoutOptions.flexBasis = ASRelativeDimensionMakeWithPoints(10); } // width 300px; height 0-150px. @@ -443,12 +440,12 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); for (ASStaticSizeDisplayNode *subnode in subnodes) { - [ASLayoutSpec layoutOptionsForChild:subnode].flexGrow = YES; + subnode.layoutOptions.flexGrow = YES; } // 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. - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[0])].flexBasis = ASRelativeDimensionMakeWithPercent(0.5); + ((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.flexBasis = ASRelativeDimensionMakeWithPercent(0.5); static ASSizeRange kSize = {{200, 0}, {200, INFINITY}}; [self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil]; @@ -464,7 +461,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {50, 50}; for (ASStaticSizeDisplayNode *subnode in subnodes) { - [ASLayoutSpec layoutOptionsForChild:subnode].flexBasis = ASRelativeDimensionMakeWithPoints(20); + subnode.layoutOptions.flexBasis = ASRelativeDimensionMakeWithPoints(20); } static ASSizeRange kSize = {{300, 0}, {300, 150}}; @@ -482,9 +479,8 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {3000, 3000}; ASRatioLayoutSpec *child2 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.0 child:subnodes[2]]; - ASLayoutOptions *layoutOptions2 = [ASLayoutSpec layoutOptionsForChild:child2]; - layoutOptions2.flexGrow = YES; - layoutOptions2.flexShrink = YES; + child2.layoutOptions.flexGrow = YES; + child2.layoutOptions.flexShrink = YES; // 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. @@ -509,13 +505,13 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) NSArray *subnodes = defaultSubnodes(); ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {300, 50}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[0])].flexShrink = YES; + ((ASStaticSizeDisplayNode *)subnodes[0]).layoutOptions.flexShrink = YES; ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 50}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[1])].flexShrink = NO; + ((ASStaticSizeDisplayNode *)subnodes[1]).layoutOptions.flexShrink = NO; ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {200, 50}; - [ASLayoutSpec layoutOptionsForChild:((ASStaticSizeDisplayNode *)subnodes[2])].flexShrink = YES; + ((ASStaticSizeDisplayNode *)subnodes[2]).layoutOptions.flexShrink = YES; // 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. diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index 2be42824b1..d1f49351a2 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -136,7 +136,6 @@ static const CGFloat kInnerPadding = 10.0f; { _imageNode.preferredFrameSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); _textNode.flexShrink = YES; - _textNode.flexGrow = YES; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; stackSpec.direction = ASStackLayoutDirectionHorizontal;