From 086bd8a52ba10d0ad59bd9ebdc4f11da2a2ee1f3 Mon Sep 17 00:00:00 2001 From: Sam Stow Date: Sat, 23 Jan 2016 15:04:06 -0800 Subject: [PATCH] [ASRelativeLayoutSpec] New core layout spec type: Relative Position, now powers Center as well. This spec allows positioning a child at any 9-part box position (corners, edges, or center). --- AsyncDisplayKit.xcodeproj/project.pbxproj | 17 +++ AsyncDisplayKit/AsyncDisplayKit.h | 1 + AsyncDisplayKit/Layout/ASCenterLayoutSpec.h | 17 ++- AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm | 68 +++------ AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h | 73 ++++++++++ .../Layout/ASRelativeLayoutSpec.mm | 117 ++++++++++++++++ .../ASCenterLayoutSpecSnapshotTests.mm | 30 ++-- .../ASRelativeLayoutSpecSnapshotTests.mm | 130 ++++++++++++++++++ ...ngeIsGivenToChildWhenNotPositioning@2x.png | Bin 0 -> 4955 bytes .../testWithOptions@2x.png | Bin 0 -> 6221 bytes .../testWithOptions_CenterX@2x.png | Bin 0 -> 6922 bytes .../testWithOptions_CenterXCenterY@2x.png | Bin 0 -> 6662 bytes .../testWithOptions_CenterXEndY@2x.png | Bin 0 -> 6474 bytes .../testWithOptions_CenterY@2x.png | Bin 0 -> 6055 bytes .../testWithOptions_EndX@2x.png | Bin 0 -> 5710 bytes .../testWithOptions_EndXCenterY@2x.png | Bin 0 -> 5811 bytes .../testWithOptions_EndXEndY@2x.png | Bin 0 -> 5534 bytes .../testWithOptions_EndY@2x.png | Bin 0 -> 5894 bytes .../testWithSizingOptions@2x.png | Bin 0 -> 6221 bytes ...thSizingOptions_SizingMinimumHeight@2x.png | Bin 0 -> 4847 bytes ...ithSizingOptions_SizingMinimumWidth@2x.png | Bin 0 -> 2099 bytes ...zingMinimumWidthSizingMinimumHeight@2x.png | Bin 0 -> 1448 bytes ...ngeIsGivenToChildWhenNotPositioning@3x.png | Bin 0 -> 10308 bytes .../testWithOptions@3x.png | Bin 0 -> 12389 bytes .../testWithOptions_CenterX@3x.png | Bin 0 -> 12505 bytes .../testWithOptions_CenterXCenterY@3x.png | Bin 0 -> 12274 bytes .../testWithOptions_CenterXEndY@3x.png | Bin 0 -> 12004 bytes .../testWithOptions_CenterY@3x.png | Bin 0 -> 12114 bytes .../testWithOptions_EndX@3x.png | Bin 0 -> 11609 bytes .../testWithOptions_EndXCenterY@3x.png | Bin 0 -> 11738 bytes .../testWithOptions_EndXEndY@3x.png | Bin 0 -> 11338 bytes .../testWithOptions_EndY@3x.png | Bin 0 -> 11827 bytes .../testWithSizingOptions@3x.png | Bin 0 -> 12389 bytes ...thSizingOptions_SizingMinimumHeight@3x.png | Bin 0 -> 9534 bytes ...ithSizingOptions_SizingMinimumWidth@3x.png | Bin 0 -> 3946 bytes ...zingMinimumWidthSizingMinimumHeight@3x.png | Bin 0 -> 2696 bytes 36 files changed, 380 insertions(+), 73 deletions(-) create mode 100644 AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h create mode 100644 AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm create mode 100644 AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXEndY@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@2x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXEndY@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@3x.png create mode 100644 AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@3x.png diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 8fe736fc..5ca1e6d8 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -268,6 +268,11 @@ 767E7F8E1C90191D0066C000 /* AsyncDisplayKit+Debug.m in Sources */ = {isa = PBXBuildFile; fileRef = 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */; }; 81EE384F1C8E94F000456208 /* ASRunLoopQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; }; + 7A06A73A1C35F08800FE8DAA /* ASRelativeLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */; }; + 7A06A73B1C35F08800FE8DAA /* ASRelativeLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */; }; + 7AB338671C55B3460055FDE8 /* ASRelativeLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */; }; 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; }; 92DD2FE61BF4D05E0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; @@ -739,6 +744,9 @@ 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AsyncDisplayKit+Debug.m"; sourceTree = ""; }; 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRunLoopQueue.h; path = ../ASRunLoopQueue.h; sourceTree = ""; }; 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRunLoopQueue.mm; path = ../ASRunLoopQueue.mm; sourceTree = ""; }; + 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRelativeLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm; sourceTree = ""; }; + 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRelativeLayoutSpec.h; path = AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h; sourceTree = ""; }; + 7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRelativeLayoutSpecSnapshotTests.mm; sourceTree = ""; }; 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMapNode.h; sourceTree = ""; }; 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMapNode.mm; sourceTree = ""; }; 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; @@ -1057,6 +1065,7 @@ 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */, 056D21541ABCEF50001107EF /* ASImageNodeSnapshotTests.m */, ACF6ED531B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm */, + 7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */, ACF6ED551B178DC700DA7C62 /* ASInsetLayoutSpecSnapshotTests.mm */, ACF6ED591B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm */, ACF6ED5A1B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm */, @@ -1316,6 +1325,8 @@ ACF6ED131B17843500DA7C62 /* ASOverlayLayoutSpec.mm */, ACF6ED141B17843500DA7C62 /* ASRatioLayoutSpec.h */, ACF6ED151B17843500DA7C62 /* ASRatioLayoutSpec.mm */, + 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */, + 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */, 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */, AC21EC0F1B3D0BF600C8B19A /* ASStackLayoutDefines.h */, ACF6ED161B17843500DA7C62 /* ASStackLayoutSpec.h */, @@ -1377,6 +1388,7 @@ 058D0A6B195D05EC00B7D73C /* _ASAsyncTransactionContainer.h in Headers */, 058D0A6D195D05EC00B7D73C /* _ASAsyncTransactionGroup.h in Headers */, 058D0A72195D05F800B7D73C /* _ASCoreAnimationExtras.h in Headers */, + 7A06A73B1C35F08800FE8DAA /* ASRelativeLayoutSpec.h in Headers */, 058D0A53195D05DC00B7D73C /* _ASDisplayLayer.h in Headers */, 058D0A55195D05DC00B7D73C /* _ASDisplayView.h in Headers */, B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, @@ -1570,6 +1582,7 @@ AC7A2C181BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */, B35062531B010EFD0018CF92 /* ASImageNode+CGExtras.h in Headers */, 254C6B7F1BF94DF4003EC431 /* ASTextKitTruncating.h in Headers */, + 7AB338671C55B3460055FDE8 /* ASRelativeLayoutSpec.h in Headers */, B35062021B010EFD0018CF92 /* ASImageNode.h in Headers */, B350621F1B010EFD0018CF92 /* ASImageProtocols.h in Headers */, 430E7C901B4C23F100697A4C /* ASIndexPath.h in Headers */, @@ -1912,6 +1925,7 @@ CC3B20851C3F76D600798563 /* ASPendingStateController.mm in Sources */, ACF6ED2C1B17843500DA7C62 /* ASOverlayLayoutSpec.mm in Sources */, 0442850F1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm in Sources */, + 7A06A73A1C35F08800FE8DAA /* ASRelativeLayoutSpec.mm in Sources */, 257754921BED28F300737CA5 /* ASEqualityHashHelpers.mm in Sources */, E52405B31C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm in Sources */, 257754AB1BEE44CD00737CA5 /* ASTextKitEntityAttribute.m in Sources */, @@ -1975,6 +1989,7 @@ 058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m in Sources */, ACF6ED611B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm in Sources */, ACF6ED621B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm in Sources */, + 7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */, 254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */, 05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.mm in Sources */, ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */, @@ -2075,6 +2090,8 @@ 9C8221981BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */, 34EFC7721B701D0300AD841F /* ASStackLayoutSpec.mm in Sources */, 34EFC7761B701D2A00AD841F /* ASStackPositionedLayout.mm in Sources */, + DECC2ED01C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */, + 7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */, 34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */, DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */, AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index 2bad5cdf..967810ed 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -45,6 +45,7 @@ #import #import #import +#import #import #import #import diff --git a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h index f8413d27..75a48443 100644 --- a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h @@ -8,7 +8,7 @@ * */ -#import +#import /** How the child is centered within the spec. */ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecCenteringOptions) { @@ -25,19 +25,22 @@ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecCenteringOptions) { /** How much space the spec will take up. */ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecSizingOptions) { /** The spec will take up the maximum size possible */ - ASCenterLayoutSpecSizingOptionDefault, + ASCenterLayoutSpecSizingOptionDefault = ASRelativeLayoutSpecSizingOptionDefault, /** The spec will take up the minimum size possible along the X axis */ - ASCenterLayoutSpecSizingOptionMinimumX = 1 << 0, + ASCenterLayoutSpecSizingOptionMinimumX = ASRelativeLayoutSpecSizingOptionMinimumWidth, /** The spec will take up the minimum size possible along the Y axis */ - ASCenterLayoutSpecSizingOptionMinimumY = 1 << 1, + ASCenterLayoutSpecSizingOptionMinimumY = ASRelativeLayoutSpecSizingOptionMinimumHeight, /** Convenience option to take up the minimum size along both the X and Y axis */ - ASCenterLayoutSpecSizingOptionMinimumXY = ASCenterLayoutSpecSizingOptionMinimumX | ASCenterLayoutSpecSizingOptionMinimumY, + ASCenterLayoutSpecSizingOptionMinimumXY = ASRelativeLayoutSpecSizingOptionMinimumSize }; NS_ASSUME_NONNULL_BEGIN -/** Lays out a single layoutable child and position it so that it is centered into the layout bounds. */ -@interface ASCenterLayoutSpec : ASLayoutSpec +/** Lays out a single layoutable child and position it so that it is centered into the layout bounds. + * NOTE: ASRelativeLayoutSpec offers all of the capabilities of Center, and more. + * Check it out if you would like to be able to position the child at any corner or the middle of an edge. + */ +@interface ASCenterLayoutSpec : ASRelativeLayoutSpec @property (nonatomic, assign) ASCenterLayoutSpecCenteringOptions centeringOptions; @property (nonatomic, assign) ASCenterLayoutSpecSizingOptions sizingOptions; diff --git a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm index 487a7e3b..147142db 100644 --- a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm @@ -23,13 +23,14 @@ sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions child:(id)child; { - if (!(self = [super init])) { + ASRelativeLayoutSpecPosition verticalPosition = [self verticalPositionFromCenteringOptions:centeringOptions]; + ASRelativeLayoutSpecPosition horizontalPosition = [self horizontalPositionFromCenteringOptions:centeringOptions]; + + if (!(self = [super initWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOptions child:child])) { return nil; } - ASDisplayNodeAssertNotNil(child, @"Child cannot be nil"); _centeringOptions = centeringOptions; _sizingOptions = sizingOptions; - [self setChild:child]; return self; } @@ -44,61 +45,36 @@ { ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); _centeringOptions = centeringOptions; + + [self setHorizontalPosition:[self horizontalPositionFromCenteringOptions:centeringOptions]]; + [self setVerticalPosition:[self verticalPositionFromCenteringOptions:centeringOptions]]; } - (void)setSizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions { ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); _sizingOptions = sizingOptions; + [self setSizingOption:sizingOptions]; } -- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize +- (ASRelativeLayoutSpecPosition)horizontalPositionFromCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions { - CGSize size = { - constrainedSize.max.width, - constrainedSize.max.height - }; - - // Layout the child - const CGSize minChildSize = { - (_centeringOptions & ASCenterLayoutSpecCenteringX) != 0 ? 0 : constrainedSize.min.width, - (_centeringOptions & ASCenterLayoutSpecCenteringY) != 0 ? 0 : constrainedSize.min.height, - }; - ASLayout *sublayout = [self.child measureWithSizeRange:ASSizeRangeMake(minChildSize, constrainedSize.max)]; - - // If we have an undetermined height or width, use the child size to define the layout - // size - size = ASSizeRangeClamp(constrainedSize, { - isnan(size.width) ? sublayout.size.width : size.width, - isnan(size.height) ? sublayout.size.height : size.height - }); - - // If minimum size options are set, attempt to shrink the size to the size of the child - size = ASSizeRangeClamp(constrainedSize, { - MIN(size.width, (_sizingOptions & ASCenterLayoutSpecSizingOptionMinimumX) != 0 ? sublayout.size.width : size.width), - MIN(size.height, (_sizingOptions & ASCenterLayoutSpecSizingOptionMinimumY) != 0 ? sublayout.size.height : size.height) - }); - - // Compute the centered position for the child - BOOL shouldCenterAlongX = (_centeringOptions & ASCenterLayoutSpecCenteringX); - BOOL shouldCenterAlongY = (_centeringOptions & ASCenterLayoutSpecCenteringY); - sublayout.position = { - ASRoundPixelValue(shouldCenterAlongX ? (size.width - sublayout.size.width) * 0.5f : 0), - ASRoundPixelValue(shouldCenterAlongY ? (size.height - sublayout.size.height) * 0.5f : 0) - }; - - return [ASLayout layoutWithLayoutableObject:self size:size sublayouts:@[sublayout]]; + BOOL centerX = (centeringOptions & ASCenterLayoutSpecCenteringX) != 0; + if (centerX) { + return ASRelativeLayoutSpecPositionCenter; + } else { + return ASRelativeLayoutSpecPositionStart; + } } -- (void)setChildren:(NSArray *)children +- (ASRelativeLayoutSpecPosition)verticalPositionFromCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions { - ASDisplayNodeAssert(NO, @"not supported by this layout spec"); -} - -- (NSArray *)children -{ - ASDisplayNodeAssert(NO, @"not supported by this layout spec"); - return nil; + BOOL centerY = (centeringOptions & ASCenterLayoutSpecCenteringY) != 0; + if (centerY) { + return ASRelativeLayoutSpecPositionCenter; + } else { + return ASRelativeLayoutSpecPositionStart; + } } @end diff --git a/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h new file mode 100644 index 00000000..ddc88c06 --- /dev/null +++ b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h @@ -0,0 +1,73 @@ +// +// ASRelativeLayoutSpec.h +// AsyncDisplayKit +// +// Created by Samuel Stow on 12/31/15. +// + +#import + +/** How the child is positioned within the spec. */ +typedef NS_OPTIONS(NSUInteger, ASRelativeLayoutSpecPosition) { + /** The child is positioned at point 0 relatively to the layout axis (ie left / top most) */ + ASRelativeLayoutSpecPositionStart = 0, + /** The child is centered along the specified axis */ + ASRelativeLayoutSpecPositionCenter = 1 << 0, + /** The child is positioned at the maximum point of the layout axis (ie right / bottom most) */ + ASRelativeLayoutSpecPositionEnd = 1 << 1, +}; + +/** How much space the spec will take up. */ +typedef NS_OPTIONS(NSUInteger, ASRelativeLayoutSpecSizingOption) { + /** The spec will take up the maximum size possible */ + ASRelativeLayoutSpecSizingOptionDefault, + /** The spec will take up the minimum size possible along the X axis */ + ASRelativeLayoutSpecSizingOptionMinimumWidth = 1 << 0, + /** The spec will take up the minimum size possible along the Y axis */ + ASRelativeLayoutSpecSizingOptionMinimumHeight = 1 << 1, + /** Convenience option to take up the minimum size along both the X and Y axis */ + ASRelativeLayoutSpecSizingOptionMinimumSize = ASRelativeLayoutSpecSizingOptionMinimumWidth | ASRelativeLayoutSpecSizingOptionMinimumHeight, +}; + +NS_ASSUME_NONNULL_BEGIN + +/** Lays out a single layoutable child and positions it within the layout bounds according to vertical and horizontal positional specifiers. + * Can position the child at any of the 4 corners, or the middle of any of the 4 edges, as well as the center - similar to "9-part" image areas. + */ +@interface ASRelativeLayoutSpec : ASLayoutSpec + +// You may create a spec with alloc / init, then set any non-default properties; or use a convenience initialize that accepts all properties. +@property (nonatomic, assign) ASRelativeLayoutSpecPosition horizontalPosition; +@property (nonatomic, assign) ASRelativeLayoutSpecPosition verticalPosition; +@property (nonatomic, assign) ASRelativeLayoutSpecSizingOption sizingOption; + +/*! + * @discussion convenience constructor for a ASRelativeLayoutSpec + * @param horizontalPosition how to position the item on the horizontal (x) axis + * @param verticalPosition how to position the item on the vertical (y) axis + * @param sizingOption how much size to take up + * @param child the child to layout + * @return a configured ASRelativeLayoutSpec + */ ++ (instancetype)relativePositionLayoutSpecWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition + verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition + sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption + child:(id)child; + +/*! + * @discussion convenience initializer for a ASRelativeLayoutSpec + * @param horizontalPosition how to position the item on the horizontal (x) axis + * @param verticalPosition how to position the item on the vertical (y) axis + * @param sizingOption how much size to take up + * @param child the child to layout + * @return a configured ASRelativeLayoutSpec + */ +- (instancetype)initWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition + verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition + sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption + child:(id)child; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm new file mode 100644 index 00000000..7a1a0ea5 --- /dev/null +++ b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm @@ -0,0 +1,117 @@ +// +// ASRelativeLayoutSpec.mm +// AsyncDisplayKit +// +// Created by Samuel Stow on 12/31/15. +// + +#import "ASRelativeLayoutSpec.h" + +#import "ASInternalHelpers.h" +#import "ASLayout.h" + +@implementation ASRelativeLayoutSpec + +- (instancetype)initWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption child:(id)child +{ + if (!(self = [super init])) { + return nil; + } + ASDisplayNodeAssertNotNil(child, @"Child cannot be nil"); + _horizontalPosition = horizontalPosition; + _verticalPosition = verticalPosition; + _sizingOption = sizingOption; + [self setChild:child]; + return self; +} + ++ (instancetype)relativePositionLayoutSpecWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption child:(id)child +{ + return [[self alloc] initWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOption child:child]; +} + +- (void)setHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _horizontalPosition = horizontalPosition; +} + +- (void)setVerticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition { + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _verticalPosition = verticalPosition; +} + +- (void)setSizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _sizingOption = sizingOption; +} + +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize +{ + CGSize size = { + constrainedSize.max.width, + constrainedSize.max.height + }; + + BOOL reduceWidth = (_horizontalPosition & ASRelativeLayoutSpecPositionCenter) != 0 || + (_horizontalPosition & ASRelativeLayoutSpecPositionEnd) != 0; + + BOOL reduceHeight = (_verticalPosition & ASRelativeLayoutSpecPositionCenter) != 0 || + (_verticalPosition & ASRelativeLayoutSpecPositionEnd) != 0; + + // Layout the child + const CGSize minChildSize = { + reduceWidth ? 0 : constrainedSize.min.width, + reduceHeight ? 0 : constrainedSize.min.height, + }; + ASLayout *sublayout = [self.child measureWithSizeRange:ASSizeRangeMake(minChildSize, constrainedSize.max)]; + + // If we have an undetermined height or width, use the child size to define the layout + // size + size = ASSizeRangeClamp(constrainedSize, { + isfinite(size.width) == NO ? sublayout.size.width : size.width, + isfinite(size.height) == NO ? sublayout.size.height : size.height + }); + + // If minimum size options are set, attempt to shrink the size to the size of the child + size = ASSizeRangeClamp(constrainedSize, { + MIN(size.width, (_sizingOption & ASRelativeLayoutSpecSizingOptionMinimumWidth) != 0 ? sublayout.size.width : size.width), + MIN(size.height, (_sizingOption & ASRelativeLayoutSpecSizingOptionMinimumHeight) != 0 ? sublayout.size.height : size.height) + }); + + // Compute the position for the child on each axis according to layout parameters + CGFloat xPosition = [self proportionOfAxisForAxisPosition:_horizontalPosition]; + CGFloat yPosition = [self proportionOfAxisForAxisPosition:_verticalPosition]; + + sublayout.position = { + ASRoundPixelValue((size.width - sublayout.size.width) * xPosition), + ASRoundPixelValue((size.height - sublayout.size.height) * yPosition) + }; + + 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; +} + +- (CGFloat)proportionOfAxisForAxisPosition:(ASRelativeLayoutSpecPosition)position +{ + if ((position & ASRelativeLayoutSpecPositionCenter) != 0) { + return 0.5f; + } else if ((position & ASRelativeLayoutSpecPositionEnd) != 0) { + return 1.0f; + } else { + return 0.0f; + } +} + +@end diff --git a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm index 10c129f1..f6ba9da1 100644 --- a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm @@ -38,10 +38,14 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}}; - (void)testWithSizingOptions { - [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionDefault]; - [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumX]; - [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumY]; - [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY]; + [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone + sizingOptions:ASCenterLayoutSpecSizingOptionDefault]; + [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone + sizingOptions:ASCenterLayoutSpecSizingOptionMinimumX]; + [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone + sizingOptions:ASCenterLayoutSpecSizingOptionMinimumY]; + [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone + sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY]; } - (void)testWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)options @@ -51,14 +55,7 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}}; ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); foregroundNode.staticSize = {70, 100}; - ASLayoutSpec *layoutSpec = - [ASBackgroundLayoutSpec - backgroundLayoutSpecWithChild: - [ASCenterLayoutSpec - centerLayoutSpecWithCenteringOptions:options - sizingOptions:sizingOptions - child:foregroundNode] - background:backgroundNode]; + ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:[ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:options sizingOptions:sizingOptions child:foregroundNode]background:backgroundNode]; [self testLayoutSpec:layoutSpec sizeRange:kSize @@ -97,14 +94,7 @@ static NSString *suffixForCenteringOptions(ASCenterLayoutSpecCenteringOptions ce foregroundNode.staticSize = {10, 10}; foregroundNode.flexGrow = YES; - ASCenterLayoutSpec *layoutSpec = - [ASCenterLayoutSpec - centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringNone - sizingOptions:{} - child: - [ASBackgroundLayoutSpec - backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]] - background:backgroundNode]]; + ASCenterLayoutSpec *layoutSpec = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:{} child:[ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]] background:backgroundNode]]; [self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier:nil]; } diff --git a/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm new file mode 100644 index 00000000..468b515a --- /dev/null +++ b/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASLayoutSpecSnapshotTestsHelper.h" + +#import "ASBackgroundLayoutSpec.h" +#import "ASRelativeLayoutSpec.h" +#import "ASStackLayoutSpec.h" +#import "ASLayoutOptions.h" + +static const ASSizeRange kSize = {{100, 120}, {320, 160}}; + +@interface ASRelativeLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase +@end + +@implementation ASRelativeLayoutSpecSnapshotTests + +- (void)setUp +{ + [super setUp]; + self.recordMode = NO; +} + +- (void)testWithOptions +{ + + [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionStart]; + [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionCenter]; + [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionEnd]; + +} + +- (void)testAllVerticalPositionsForHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition { + [self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionStart sizingOptions:{}]; + [self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionCenter sizingOptions:{}]; + [self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionEnd sizingOptions:{}]; +} + +- (void)testWithSizingOptions +{ + [self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart + verticalPosition:ASRelativeLayoutSpecPositionStart + sizingOptions:ASRelativeLayoutSpecSizingOptionDefault]; + [self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart + verticalPosition:ASRelativeLayoutSpecPositionStart + sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumWidth]; + [self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart + verticalPosition:ASRelativeLayoutSpecPositionStart + sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumHeight]; + [self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart + verticalPosition:ASRelativeLayoutSpecPositionStart + sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumSize]; +} + +- (void)testWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition + verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition + sizingOptions:(ASRelativeLayoutSpecSizingOption)sizingOptions +{ + ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); + foregroundNode.staticSize = {70, 100}; + + ASLayoutSpec *layoutSpec = + [ASBackgroundLayoutSpec + backgroundLayoutSpecWithChild: + [ASRelativeLayoutSpec + relativePositionLayoutSpecWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOptions child:foregroundNode] + background:backgroundNode]; + + [self testLayoutSpec:layoutSpec + sizeRange:kSize + subnodes:@[backgroundNode, foregroundNode] + identifier:suffixForPositionOptions(horizontalPosition, verticalPosition, sizingOptions)]; +} + +static NSString *suffixForPositionOptions(ASRelativeLayoutSpecPosition horizontalPosition, + ASRelativeLayoutSpecPosition verticalPosition, + ASRelativeLayoutSpecSizingOption sizingOptions) +{ + NSMutableString *suffix = [NSMutableString string]; + + if ((horizontalPosition & ASRelativeLayoutSpecPositionCenter) != 0) { + [suffix appendString:@"CenterX"]; + } else if ((horizontalPosition & ASRelativeLayoutSpecPositionEnd) != 0) { + [suffix appendString:@"EndX"]; + } + + if ((verticalPosition & ASRelativeLayoutSpecPositionCenter) != 0) { + [suffix appendString:@"CenterY"]; + } else if ((verticalPosition & ASRelativeLayoutSpecPositionEnd) != 0) { + [suffix appendString:@"EndY"]; + } + + if ((sizingOptions & ASRelativeLayoutSpecSizingOptionMinimumWidth) != 0) { + [suffix appendString:@"SizingMinimumWidth"]; + } + + if ((sizingOptions & ASRelativeLayoutSpecSizingOptionMinimumHeight) != 0) { + [suffix appendString:@"SizingMinimumHeight"]; + } + + return suffix; +} + +- (void)testMinimumSizeRangeIsGivenToChildWhenNotPositioning +{ + ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + foregroundNode.staticSize = {10, 10}; + foregroundNode.flexGrow = YES; + + ASLayoutSpec *childSpec = [ASBackgroundLayoutSpec + backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]] + background:backgroundNode]; + + ASRelativeLayoutSpec *layoutSpec = [ASRelativeLayoutSpec + relativePositionLayoutSpecWithHorizontalPosition:ASRelativeLayoutSpecPositionStart verticalPosition:ASRelativeLayoutSpecPositionStart sizingOption:{} child:childSpec]; + + + [self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier:nil]; +} + +@end diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..02717f8fdb7afa87892b61d4e4638fa5ea022138 GIT binary patch literal 4955 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV07SM1B&RJJqwaxEDmyaVpw-h<|UBBS>O>_ z%)lU~3c`$@K`I}Bf-;#d{vkk`35Y>p0T63IX&{>`X7S`@Kt7j-r;B4q1>>6=2YHVe z@Gv`mzhA=i|1g_b@d42VjHz6f=Pmo~nI(UmJMdB2p@D&s$(8Zw|JXk^DbP0l+XkKb|Z(7 literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..50cb613c24dffd7fe74cd067e3a7829e97f311fa GIT binary patch literal 6221 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV07SM1B&RJJqwaxEDmyaVpw-h<|UBBS>O>_ z%)lU~3c`$@K`I}Bf-;#d{vkk`35Y>p0T63IX&{>?%c^*aIgmEGSU5_q!NUO2h)L-qXmEGiR(e%$;0C-ndWGmpWBvixFzTHCf6jXPk`g@Hd)4;m97BFcvPHIrh^e_VH(vb>aIQ_|g zz0Sx-(q2GYHNL90PXgHvKsn+lM3;J_kA)(txUt>4G^%_3;0{a&u0b?S{r zz2EyxlLYAodB6+k0S~E3NFI2!X2& zlDbDz+GzH~RgR99X((A`v?4$*M@MVV(IyAZX3l7n139aVHaSqrQH&->J+LG3|NpTo zmU|c&xH~{Sh_^R)PfRuxV0L&qf6KSzVgZH=TTA^(^wV!Yrrz22X2l@&TqZO)UxJi27l0ic zp6Q?t&eS-cH8;A~T846Xb|SH)gJc9e>L2?OgN4 zi=ZF&$F=_1H`(Fwvh8Zq5nUVwl?M|_AgSF1*sVJJ6qwpmmxdGe!&j{*-{-POneR2- zc?J|9py&z!Mpye1XXNObTdt?Qm#`n!hb!)XuR<`ofc>w?ms1J)p&rlB zp7vT#*bk#gZZyde$~L1(j%uackG&^b6_~-LERaYz2^xy2pMD^EHS;`BJgTe~ HDWM4fnCrt8 literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..69e7392384b2717608d347dfbbf0aa940f24a3e7 GIT binary patch literal 6922 zcmeHLeNYo;8haY z@^A1aup(`@0f5jA+(Oc`Ua-N<$kLRIYGsi5>8l`}Avp0h(o<|#MdB5WgJ}Vob7p0EJA3ROErLuQ(u zgo2nGK{f(>>Jk|Wn&Vs6i3Fj7b8(3mGYXk{9B9Bp zfxN*(n5;3kG0y(JSQN-J-Mhfa&7u5H&(NQcSI6%J8Os-OfV76u8m!S?*~Ft;MVL$P zSPjr=eRD*Q(TSJFw8vBw4V*ANkLo!gns}1Js zP`prwcOOH1qwG&%e+v6k*k6VHRoGvJ{ey&eO7ag9%TtnnkXRn{{j>1$l=MH%!ju^R zz_Ne;%JnfkA5?P(!AEy5louxAf}3u(W#LkEwx)UG4AHK=w^5<5ixVz7oyKa{XPBgG zgnrPM6yn$~m_IPFq`78aDq&0>{qXxd>>3-KERt88LbBR; z9}D+bR=d@&MxpF0JTXa9Gx)D+Ef;@Uv7~k^&Kq&DhGpBr7(RMDRj?&Q9vQd>dz@f< z6!?@)Gq)XH24`C0-PH+gG(cXU>%!XqTy)x<`g6|q8*$FmBl3y^2rmr;5+pTZt9(a* zJ0eisk@rqYWF+-n62j!RX*0t^?qqB7O6CQLorV`lKAilQ!H2ZD_>{H31z@$7p~sVy=Z3m^zb25{Ui5qr?%Vc{n2=%bT? zzTo`vP}HfiM?(@%l&Vd0#}m%(pxzX`*l7GJW0^8M;Yse`=Hj<$(xPCdWBTe4o-<`Lk|4nv zc+NzyEj`xVA#z5KS0xVqI-i6JSw5++$Fv+8F`c;?HZ?hV!WS&V$`lRe^=6L5Cc`~t zM&eG+aYX)rYKf1kphJB;=XbN;&Hilm7mfeBqERZA&;XN@)N?4m0sixLgS$a+Le>kA z!-DdmnX>nlO^KepZrI;=B{Mz$g>aXH>ItEOdjz1bavkQ<4|@UXF)A(~K`*a!`iG9K zCx#+Dd%BenW)-lM9rWdK_a7b-(9R)+1{6>e_IKm^^ZgSYc#o0UW))#z*ZYqk*m`W{o(Sk$7M{>3J6;z zYMXfHkVmWJA=Dq(`o(ImMUs-Be0gZsOXoYM2lm|e2(&3zKsc@-jl@(e2+8*bbKgqA_os(HJ^bkb>x*MmLF7-0 V4ZlgtghvvP{`y-f=aPwF7(TbRz0z`t4O*y(icUp0gcdRyqSBTzgiWnNb($Ku0|}T6=m><#w=Ol*T#Uwk6u3p(*lFdAQ47O1jo`jI#xyz+V0%j%9Qoj{+Zk+C#UE1 zIVbP?-1olcJx^)Kb=G$k{?QB3^;O0f<_H3yVhUgq(y$CmzB|O%^nKk<4-uTOeU5O( zc#nc5z9B&Ka3OV_DymGB4EK#k}PeEy?V1 zfU(rEVI%pUuS|%pfcEd=B1A?DW0l`IGC#`;%~9 zugBZ?cXPB_ab~@pxTbu%URqKUBbb?(d92Y9QUQ@V@i=Iy7C5j}G{7~$V1jlp!ls8>(s`Z0+nBzQ^2__1bP*hF$ zwY&KjJZZ36Iw#l~Go4l^(H=uM>3~m=hAv0xZXWJhie}dxY!FA0hG98k)0mVyB1HXa zMNXlUm(;3bYO9yvYNZArvHs8quqv}JCCR3oYHM9fd0*aNpbV{3eU+| zJ~ZM+=Sj<^(X9v6M3$jujn%mbA0+6TUL1*FiTA8~MG{*HUY7Lm(_9jI=;e|nCov_B zMk+4$hK~$(pM4b^g%wFp>EF`RM#So##;cODXyS<62QoJol|e#bRr-=SmS&b_Hk#R_ z!6pqhHz$hTq$4nb>yts7I((XplvY@w0#+?mfIP#%#9_^a&ip!NE)M0M0#9Br8tfdx zyp*)Ir1*qW1r%n}K~aTIxJB^$@Q{SM?4es5RL|l&7%|rv2w@GON;E59wc}qYHWzA0 zdu%N?hw7tsXY*)jjX_qxCMd(okI zV-iEz%|HlGF{m66_#fux*F{|+q^F(JIy%|1>8vG^aWFd&LN5d6qT_xQetDpW&xXev d7#@^7wrW{H&9};j@b4Lr@&5MID=Ea$e*m2=yp;d| literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..385fc3e81798df41a041666071cadc2b97ceda14 GIT binary patch literal 6474 zcmeHJZ%k8H6u4a`6LoAFG0szFB%hR#}Kq&wajR1$1xXw=Y0aBEmkqYX&qW^$DLiEem z7Xc7Ho1I8z_IplfjLuJ6y%w%0ob0HBQyy61ci}6ds(BM!TQbv9)|McHy=OkdQV3qk zliI}D>7ZrF%8C!~+(Ji(iW%3q;flYLLU0Mmems+Sa*B2Linre-lr+EyrBkN?FZs74 z$iRlLq@h47y6a0!4j4iKUvsKF@c&P69^HHOy!vkgPlIF)XeW<1S0ae=g8tO%DFcFJ zf!m{#7n8Cr8t~2g8wPGo88jdaoLB$*+R<}U2JTue$Rx#4ihF?q^@A%HTycbb=5;y{ zitow$+%(5I6e5^*6~WwM0cE~n|JuN$*A&P3tLQE0cXMq==MhbXEXj-rA?e-V-?I&! z?{+J8CY@_-r-0<5Z!WLKo-9v`oYA|IuF^9r8?;H`us7xb3|~}XwSQ0PWzkB#ePVBO zn>(*B|N6|bkWc3*zZia4b(J2&VXy3tpeb`_|4`!`#|{&-qj70cHNk>0r8>Ohds9y= zFn98*L)@dsyvQ?nwDXfg;*9txjf2>+2{9D z3bYGCu{Cz4N2+_HThRF9v{|wFuFT@IvObr~>+>8p6HQ0Ww(=Ohzn(HWN7N35$&}z6 zpKih9ox5;*E%mUA@UsMgR?X##bJg z08Cj-#~t3b>#-P6X8G5F>V@IF6UXQusOIiok)dFW07zW~t-+5B@2o)SIx+4m^t=hM z{=&+rR)d$wmp91uo7=05GqFO}5siW}6LI}R^Z8-ED84O2oeRA%4_i^kPiJH@7RBI~ z*K!?24|G5Pnx~ut_;#hk)M^3}xvBM`j3{g04sr%A%liw+`~vjYgaT|2Ri>>gIilH>Xw43UKW)*}Mlx3m6 z%<^!W0t3+u)L!quO^l7~J#TQ{GNt}=f2z^cq2UOB)X<@Tze(Bq~#E%}m P0&rxeuS%;=B`tpe;{dF1 literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..28036afad5bf216b5f09517165fb1054933336bb GIT binary patch literal 6055 zcmeHLeM}Q)7=Q1MLahZ!6fGzU2AN@Oln-SCgJ(shW3Y~aUpOd{3F<&HabQRF>JYO` z2GYb2kWnVY4}!S4i4zLlNKl4gMe$?E$L1U$I;xZ@AG3Sk>-CngCjD#4vRsqv-M#m_ z=iYnod7j_%{63LIuW=N(2><|&(unXF0B{NbjO5$H5#P2pbOGBLvql2Ww$B@cC(|+_ zHtYmo_9C=l(ikrT9Gtf`{H<8H$Ki&48n`WH_V9Rm;o^<1PvL%(G<-#DHumUF>!EOe zK0)@E8FO$Fi+DHwqhlqz)13E|Jqvr$Nn!RPIr_WfZ^(I6TJSi2;+9aX1B6g)2=)L9 zY!ttWPTmw;N5(HO-zz-m z>I^Q2U97%#>oQ{w*MQWa&F1H;{0Y48jzjI}U5hyq%mQgjW+vh-B$zkRcOi^5$ER>j zbpbQ?W+9*2yx`ug6pJ|wlYy^CnOW+NVpztbkGsa-x0v$)0*albD9{6Zrp$;hW6jx- zn4X;_^U_1-E#|nF=Dsu?F#o1|PySr6+(o9U!iy`sTTr~{Q(-_*aUQXnCmo^cq-Hec z0rGy@s}+nXPyQVS{t0UwX@5|$ju#}2Dnc=%xsJT}40(#YUzz3IbP$b^K-gqbxICSR zwh7zYU)n0I5u_Fsd!gtiPoQ{3NOd=kMtZ92GYp{6AMj4aaV>zZNo~lUVTaHqmgbaqLW9yJq%|VPr`Ha z(+0Y3p~rB!=*8`-!rm;~u+ZU6(TX@yebdVoeRMZRlz0TWf}jLNO2Ab*_1WpflQru+ z8;4_U!m@h4J#IWhd7qXBpbQ%1hJ46{?~+jx7Jm*S~!kWb&xm+r7PJ=Lv+{#1K^Dsr=a_Qe55xSj<#*R1x_H5~2<>#l~Xr5H6eN)(CFdP)!2MF>cv7Z=)-7 zE=alD#!&)lwX85{UzU3NzWHXk3wC6Ys9AhoXO~cIzYKM;fH0ZV4mh7agnzms%#TU{ zT0qkbJU2^Ae%sq=lMB@NFPbWLiWsMuSVd)P1Tm?QIoq3GWKO@$b>1ol8b)U$;g2WAvpX>A~A}m88%DVPBdxM0aja zu&46+9D1sYkZdq8MYn6ntb4nvi}{v2tRa5$Ha1Kf{Ir4g0beLm^2l0?fN7Qn4V7K_ z8@qp{`+rgPTq}r-;PPit5sAkAXwl>?)*OIyktq)FpKy^qKvC(Qav&^tE!59}bX9ct IS&4k#pTAf@2mk;8 literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..692c2a4e84f552eff3e4bf5b1aff535e3e29217c GIT binary patch literal 5710 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV07SM1B&RJJqwaxEDmyaVpw-h<|UBBS>O>_ z%)lU~3c`$@K`I}Bf-;#d{vkk`35Y>p0T63IX&{@MciEF~+zbp{H$7b(Ln;{G+&IX~ zY{uJA@Msv4**`119Vwf$kR*y9i1+0+=978V+T%?U71V4QMb zM#H7+-tYhL7=y%m4&VPhon^|gqbDI2-ECkEU`l54ir3%!+4u}d%z&@{eY{YBl(;&` zB@E1^%wi6lJ)9b~d%v7JZvYZIVDV>fy{AKF%pABw7%(03Pj%EGs8KT-BIt>AG(<*2 zWV9R^Em=qFn$g;Kv^_F3TWIz34)8ND{QqyGn)M6V$bANC z9l)R}pqB9BcKbbOlUkte&)s^@0~ahT!1hXHm@i=PQt&x&VLSic=jk&*4pjK_WB30_ z4GRkkAWioRc@B(I9A-2u%$Kh^4{3Hg{PP4ZM%IEit@^pO>_ z%)lU~3c`$@K`I}Bf-;#d{vkk`35Y>p0T63IX&{?BW42B59UyJu>Eakt!T9FJ?m`wr z9+!h>?K5kgDxL|%YE@=`XyX-n@cnbG{lC-$49q+RAmWbUhnsJ#XXmbeYYG+lBYlCP zit#Jc8K{!uJQ)oAxjRmte{viuBIUrlU}Zlen?ynbBU_*31qQj>1;O*-A|?$|4#DzJ z(`1YnFxqT;xXcbNlEGlwu*?pkS;8XCfw>~*ux~9~;g&t%Bxxxq_{Vji1O=?(FSYQOsDI4+}m^B(_G%SkOuX>$61C%=y;{H8ddSZLN z+JX$3Igs4A23Rn7DX1-YalQNAFUd5J@g39u&(4pk3-u&quK9m?j6tqAa{B*SbKU)`R0!BuU#a=&?QBjBDRy;88S@&LjfFZmHGX|v zw7sqk?C(cU|38~OEk0C;fQ|e2i2VF^mPMquc`~F(C}oy%;5@=2^0(?@wEbbQzdwGe z|Ll8uy%r%GB`Om*5GeRn!yKM8W+jF{bmNaiq{8|jXUUN<0$0EZ3+^@u z1~4TudEJkL*R3{x_BMJtWadCC)-BQoz>3w!;pJ^_SY_DKzW=*Er$%otv|cJ>W^>?d z;nb+DehI5fK79E8PnB`$#zIIPej)DwgGQqP?n4VP{}TND}Q2@F#l zW;9&dJ{{Hy;NY)+A1@RjB@L~R-?H&E2yqAp{Q7nYR*61*`2MdqlUMR%NPPwj6h6fm?>p6P)1YAX!aQ`Q-B>5niRAK2M$bXeBXMIeLA#S<1yHfa)2R&p>Fzt-)qe( zARV@U{}UNl1fb(C4UMYIaSVHb!$gqcyrI#MneD(v{(U98KStku2I+e40M<6V4SBGE z8-uh13>M!G-fej|dqT{UL!d4a#F~=Vu<@8tLq@~IU^JZoGdkV!&I4w>HraIVX!V=G Pv1A5MS3j3^P6O>_ z%)lU~3c`$@K`I}Bf-;#d{vkk`35Y>p0T63IX&{>`r`2m(3y`+(ba4!+V0?39_rxO( zJkE|!=YOenYB*UL8~*&{g-NzT3*JBfUH4};BQuY|0R|v(!SF+5S^CYg-0M(*5BUxZ zUs$h*C$LE*G%&JBbVv#?By(T?V`2{#5MW?+SlbVj0ZAvZu^hN@XsaDufW?6^;B_)c zV?smY3`RzSZ3S!nVFHYd0Ss4uLCj51NONH5(T#b187APsAi}WK4%OOUTVMjC){X}9 zXp$PuK%>P4yi6V~94V=RiqtnWE!ZtlZgM9Uw8S_>S>%7CUSEi zm1&H*0>i8W7L4uxel0Bj&tnX#aeMUtKlPrNeSc1a^W%djK~?a91EtJN3pjg(3tp_3 zulj!804(<7Q~l@J)8e=K99a1AK?=A+eXxs>@dC>+PKz(s`S<=#p8;}nLd{S8_^z1W z&sb!n`28T2=Q?Qt2Hymr1@(U~?5=MEyZPAk|FiFJ`LimOiLaMk9a8&W=jCWnGw?gG zaDUy4yY`2{Zhm~a{%6pWTjszps3 zr{TJUL*?{zrR)1F8QYIFPlg3DivwmL|9@t#yFY6t!BC0cC$jU~S;B#AzCZJ4=xM^C z@@eUbt@*$(AP~s=fBK$YAEibxRHo~@uB$C37|8$6=10|CH6j=)^htU;!arCU82X{N uSx4)d(b^Z>U>|Ld@bnC^7Fzwh1N?ezvgvPM=>wa(3=E#GelF{r5}E*4X}v7~ literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7011b35abfc1c05b07a53f54ed35d428b20e78d4 GIT binary patch literal 5894 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV07SM1B&RJJqwaxEDmyaVpw-h<|UBBS>O>_ z%)lU~3c`$@K`I}Bf-;#d{vkk`35Y>p0T63IX&{@cV*UiDpFrBh)5S5Qg7M9b(}hPI zc$^)d&fj9s$isZ#b*w~s~3m4#MU|MkP zI7lN<+K`zkA?IP#e7FG90)`b|4Z-Ffa5&SzAQ8Re+H#mc1JFZRwW!v9&4dYzT00uZ zqe*Hs1C16J@G^O{a3sA3s{eR=KIe=B*-U(%?JA&J>cApK#sCJh#$={${k`c$Gr_eJ zN5k=_|9@#c`F@T?W)hz#sIqKyWd>%x45s5OV)0eypBN>Bs!sui{?q$E&pkbPpW1^7 zB_2kgnoUPafPvLP*g|c?k4x2R(tpwJ)lM=uuaLdg28)%N{I`A|<2Q?-o%VaVe%7fs9`%0jGYyi1fgbPz zdcZ?!5|Rhr?H+O^*7irLyU|w);eY{Rjq6 LS3j3^P6y-%W literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..50cb613c24dffd7fe74cd067e3a7829e97f311fa GIT binary patch literal 6221 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV07SM1B&RJJqwaxEDmyaVpw-h<|UBBS>O>_ z%)lU~3c`$@K`I}Bf-;#d{vkk`35Y>p0T63IX&{>?%c^*aIgmEGSU5_q!NUO2h)L-qXmEGiR(e%$;0C-ndWGmpWBvixFzTHCf6jXPk`g@Hd)4;m97BFcvPHIrh^e_VH(vb>aIQ_|g zz0Sx-(q2GYHNL90PXgHvKsn+lM3;J_kA)(txUt>4G^%_3;0{a&u0b?S{r zz2EyxlLYAodB6+k0S~E3NFI2!X2& zlDbDz+GzH~RgR99X((A`v?4$*M@MVV(IyAZX3l7n139aVHaSqrQH&->J+LG3|NpTo zmU|c&xH~{Sh_^R)PfRuxV0L&qf6KSzVgZH=TTA^(^wV!Yrrz22X2l@&TqZO)UxJi27l0ic zp6Q?t&eS-cH8;A~T846Xb|SH)gJc9e>L2?OgN4 zi=ZF&$F=_1H`(Fwvh8Zq5nUVwl?M|_AgSF1*sVJJ6qwpmmxdGe!&j{*-{-POneR2- zc?J|9py&z!Mpye1XXNObTdt?Qm#`n!hb!)XuR<`ofc>w?ms1J)p&rlB zp7vT#*bk#gZZyde$~L1(j%uackG&^b6_~-LERaYz2^xy2pMD^EHS;`BJgTe~ HDWM4fnCrt8 literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b14c267b42e8fb5a3472b8912e8576c6fc377a19 GIT binary patch literal 4847 zcmeAS@N?(olHy`uVBq!ia0y~yU}^xeKX9-C$q5BlPXj5&;vjb?hIQv;UIICs1s;*b z3=CqbAk63)r1AkMD3j^p9|EMAfEWZSfLH@c1KFIZ*Rw7y1=5C|E{-7;jBjon>}59O zVRra_|4ZCDhD{7v0#7#E3nzDesGdKcMP-7}k9)uWq#j^k<}uii_F((HKPn21Qx4o} zEtm7|VPum?cyPagX$6D#0+oaSsVO`LK!x3GA_q48xx9M9`*NX(JzvhH%rpdP*J$8c zz~aT!wnXtH*su%-MxE3D&sk5Oyo^Omf3I<58dx{i0w#^dNezmb9!4NtI#K})r$70x zciMN~GvVVU>&dCdK)M$&Xf+6Fa7s*SQvvc099YE2x4JE6LRs_i9=xFUpjV8wjb_Rz3|4*94iU1o=`k=#?2C|taPH$P91Ega;T^vIy7~fnu$je~B z!?f|u{t_$4yv8V-pOH;7MVVOq8aErrFtL>Jv@kRZbeyUeP)JZ<;b?IPx!26V$gJp~ zz_RF*91Dj82P2cBz|`*w4hI}K1UMR3>|tkQVsmP6;Ba|r%OPMOz{KLDp!MFdp`lSg zL4YZ+lAnnMYGn1Ok)vTb3=`3V>PB`3hX4QdHNW3sU|?|vWwf`~HcmVoAaFR~>-{Zn z3Ud}U))p6^yw9WLVSoNLKO>7;W2FKg6UQEYM*#-~jw7D+3JnZUX7wl&93+D;91i@p zSzphS@}Qn=AM>aG4`jt9fBfAi#Ns%iaVjHslH=baeLMmx57vZztV=KCa1!7al2q_G zuu-IZT2gIxlfaQC7d8%|g0R&U`#0;bD0Z-Rf>cLzS$l8XXX?n2u|$WPkVGOXidJaKvTqo6AX?_=dwiKmrrYj zsh06BOxL`&U5&$0$0MadfiZn+*LUmFPB7JdOLuG*c^xg>q9CSX;t+DLnSqg6(LsS_ z(I+_;4harMCPjg%-xVAVIB*DXG_Kgg&d9{()ZoD3^3;|?z(9bB#YsWyy<QN&{!xEH;_KAZM>Hq&9*LMg2Q)V|PWxgFvm!r97fQt=ay5#yg?@mc+ SygM*`GI+ZBxvX;Vkfo zEM{O(v;bj7*J*|cKtY*I7yl3-%>=|C@BxT5pfr#znrb*Js0&CNdb&7HIBxM=z{@c$h>1DlwXg&hlrfPzB<10xel*MUQeugmJD zOIBHCa zrkU_&95|u|F&Zd3fkj7j8W(Ry!qP^QH!=wE4WB-g`g_k}Gf7AihB|~pz=LTTmv<|h z$%ab~Qe}Jy@rcSFyOyi^GD{h3M7U0c(Ytl26SGuArUI{ZJ3@SoP0iiQla?{^&bWc> z=B0;%7Bcd#F`3Xd_b@^{Om5%1OwY>=Y(6_xy%Va_0 zRJKbSif6#Z51cxD-BveK>Ow=OFFZIEI3u)lL`Q=eoE%4kc{DW(D2x^wqlLz3*^H>_ zMytTlmIg!PXiHAq(7ea`FC4#2_2j0Zp9jM$6N|k~Hl|8jI zzUV26N<2B57@DAP6?_#cTidEg;V#9Zwknra0ShV-q=LeB7I6341d{us=|6MHKJMmb z_ct@&eDnLh-|UOgN4UzS$^Zbak-G3$03<8`n0=fS{*wBb*b6V%w%CXTpuBO~6ZnNp z*TroEz+*0dV2cX^Y{M0)|l8 zboQ1#jX|DuZ;RAj0W|0x4@jM|fcZT(VYmWc>i{N6Z~e1ndr4&!nc!uamf8G4l$4?w zZ0IDhU@LLOO_jOo=;V>Ns9AO`3r=0>UwyT#?;cX8XaV8Xzn0afE+bichE8lNe*%a$Q2-0fLsA` z1t@$&(I^V8QLX@Ga!_Il<=If$5JO2_l%u9zLG6L#dUsc80hsbJFFHK^H7wuVUruN_ zuBmbJd?oE3GCOYER?T{9-m#MSTW#GhBXEUL8-cf2+d3-bf<_=6OtmKmKly@CDGm9= zVE>nujYcuG|0>W7f`O4CQWfgU@(%@R!SDlvCse+Cez~N3rl*-&%*7K^$^f zi9w+Uj%$_N@89EET(hG4fuddKOn2wra5b%d-%#h&xJExL>)T9bsGRBU+CTCdD~_`3 zof=o~=fCW@LF$(wMbBbr8N zHDX3s23n2y#UHIkh}21`5f1%-lRDO#xNMw8*v&J{i0^LEVws@p<@lXkXomG}zy^W& z({_$qMqq@%GlyumVL*BxRAZTvpM;G@Jh4BeHiJF8@Nb%G21>I}f1NCrc4>G@EmI3I z179!w8iULG$@Yo@WpS{d7=zGsEe1L6az@;A1YsH`NGH;^Xl+)}C2qDgp!c9yng~l^ z1qaj+zaFynuuyE^Q^ligrJsp3UEVoo3@rNY-s0Bm>!HN-@W5ml~IUA7}ztTV|kGBaIh)lAN{-CjgPooPKZx{cXQWhG3fx&b0^YhHBA;{ zCbgwy3@pJ7zvULSx#e6Jk}4e}wyj=e4I-TedEANy;0o7_j= z=e@VjJ@>rN^LwA)_2cA&i2;7k`5_1rkfe)GK@i-EAn3R+0a~*DkeI*$%}+_(hcxwX zeF(nD@^nY?5#+@^t_@A7iDE$G*35W)DmY?bbA9Y!+vz!ibERX#bXg9LKPJU%Q;X2) zVePpdij-(qSMQzcQQN+Ln_6tg_Pm_;xDhY_Q3FWgS|jkm(q`xm97i^4K-jVj78@UGdE-Vq=Pat&LD>fsMT(?Mr|^9V);7*t`JfEgBI1_-wxfP~l^t|s96 z2rez*Vj0#MVC4iBonRRaRv=+b6_%s_7X|kEB_9M?U5&V!;)@^(lZ(-q8PVo$iweSN z7oTx2aNu;zw?We%`ebyNw=67|#~D_STM?Wr2zgrS1e8W5*8f9O{^0DxrQV1Nr5 zFsdw$l}bstNYuu8MD$6(YRpMS`=w7tPLh<>I^&^2M#+go6^3e7EQ(%ZNk++rNO?6~ zPmkSTUbyL=xAzgu7hFw$&OLiH>kot?5#bS`LkXC?H#lRj!gg#p3fyp8=o+^IZp`2; z12{k=@?hf(jk!ZdW5rm`WM%QRn_MZxeN_~=I)|8Rw5WklBntJ4QUULx(wk@AqpFVH z0jB-cOV;$!w@V6KPsHvfHFg^EQv zUQzNpQ zNEil%bOv*lD4oHaC14K-Fa+!Y0fqn+A;9==00uz7F2L>HIf?Sk?G-wW<7|lQg(>is zlV`Vy2}BG&+$ryOw`2>s)9TlP*~BA|2b9UI_7Z#BUU%ZH=2l^7@>an5z5m)i?Ue5b zTjmuZcY$FxGtyeI63SZ2jGT%?%YJ|D?x$%vA{C25*YACQ|H#Vr195ZdyzYm=Ft1qs zDAA3R6qQb+L>cDj&aMgR9Nq1;2zc!*di~xV7h9J0*OpH7@Fr+sX!ISRxyW`(hUsQ8 z(jl2YJ-kcv(f22KMVRrN^?Mhn(`PSI%e`lK6EIyYb`5AQGAdZonNX>6UN+_5e8f1P zb(dGfY8~64cUt!Yb^6@-K;8t_N>q9nXf84;pm1ckA2k&`ph)}9HZ@ekE5dSZ8}#lp zbsD-SwuSK~;G{TklWT}ZFe*3;CN?nx5oYx*<7b17ukwl@_y-&GE|Ha3Og|;Y2`2Cd z!vM{Vf>FWQ4&a$)J#8rJ+kNHGySySO@nD1AOY+5X*@dc7!Rw)eLkAc6m3KNo2N$NF zH{Qbt&gV)#-opqkWFtP_!w4?q7cZcJ5JiLxynyCkLzD`ezB}yd;LKUqUk{QJ4#qd_ HV=Dgv;q`6* literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..8093c8976182b151e956da8fe503b78d47c45047 GIT binary patch literal 12274 zcmeAS@N?(olHy`uVBq!ia0y~yU_QXW!1#cJ4JeZJl%)koF%}28J29*~C-V}>;Vkfo zEM{O(v;bj7*J*|cKtY*I7yl3-%>=|C@BxT5pfr#zzH(ySzR5tk)YHW=q=NCyEyuhV zO97XI`~ELY-I;gcMDJe-i8Fa05|=qm)v2^315ReKgbVW<-W@&PEstzaM1$@Du>_bhum-r=t>?2x z)dIt8G#nslXEYo}!vR=QjFu0Of^{?;M#BMX9gC}+)Z3>CbuXAjhU{m#nivA|4xj{9{(V0+Hs?B34DA(YEncOo3eNaiB@Cz*tiYxe`_6?gjSqoeSWbNXv~39X$}QYQ^b@xOq|mr!5_&uUYK!ECnC9l4eEx5 ztFBB!H-wRlV}=>``|5phpeqn=*xm?r!>E@=V`((u!SnNIUIG_Uqs7B$AwF6!jaIdg z#>i;vVYH1m+H8e2>_=PTkiN=j=VG)Ai0Dz))cpgF!~g%!_F*w_L|^ zLmn5$`~NTX9cIord^cHf#?zXHw@p!3p8x(?^LH|+TYbUk!_Qxn8(6k+T8KwKUv&TS z`;)+aH(OnO(*#Jbd&AxzzyAwOXei!TrZ=lSlTG4>`G?=aEj*wu`z*%O-N0_W|AI2T z8IX?mWkmj5|8JiHBj=TKte;<40f*NTcJZe0 z`bKVi%Jui8&Ahl;7s;r6;EF=-4XiVeLtMfl@c>>EsHV9^GSyE(wPWBbceqM!JFy1~yA?Qr!En(!$9!o5B+?Mv2a zgi!}>HvrAfVFWF&K*XINFz%Y`n08Iy@ZEbx&6C4$^#upxgAZnS((gOfH-ClH wA?dj>o>1Q2&EJk6_z8U5)h)qWES74dBvQ=9aUd`U?1w6*s_R! zsO?2x)+3ZvKpM6GQXYqIZuz>OKXX@mP?Q! zYx@o|1Ty3uK_{3Nb_eVZBFn%Gzzo0)z>3s7C;}(~D1z)ajbDkqO~HK#FBWOhHo>e(H|N z9{Wq$ki*fQt6tAm-%bOY7SLuPpK#d8*%QD<8&US9kO!EmG+P8w&L)W1vb@87Jf$a?2AaG1&=y+ zTim_y84ee3pUQL)dFV;MumgjT)IIYXCSLR&$KeZ45uHpxckrQKoyUySdk|6*5S~0> zO2obVtwz_`kuxN`F~f{_8F^xA6c7gZI0W->yF>kKn-aMyf!xy-{ocitC?Vu0AQb8F zs)gP|j^fCL$kZPOJgO1`8;3wGR>^CrK%SC7KGYlxCE-yO5S}I=z~aH;!OoM(19qN* zJpOyybh|g=8f`3Q`sL+GgwpPl;_ULQrS+as!&qXmsn&aj@!m3{e~2#FZolqs>YVM; z5LLLuyWbX@X&ddYvKfMVBAuA=cdazFT%a)bmzw%3!x1Nw%^7C=*Uq+AJ9sDW)t-}| z?4a6o>LSkCJ)j%^NmiJpxKh-x{@`Z>H(%9BV#Go(Eh&R$#PG58|ex|0;wR@N- z)==#`{_U>joWaj6^rjojNxs*zxD3ZdqJy%+AEm+6$%h_D268xpWPoG%ke71%qab<_U4dU3Yw RIexK$iuWHZ?Ayn+{0(j_dR71c literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..7e824c2073a478b89c80778318cf09300a374f80 GIT binary patch literal 12114 zcmeAS@N?(olHy`uVBq!ia0y~yU_QXW!1#cJ4JeZJl%)koF%}28J29*~C-V}>;Vkfo zEM{O(v;bj7*J*|cKtY*I7yl3-%>=|C@BxT5pfr#zZklmC@ehz@^mK6ysbG9_>-5?f zO97XI-|oNszESbu(U)8tQJ)q~?MO5{`SVYWo&CR44UB9O2?*lBZQh!Ff8}4?e{P?I zBGJ%T&&;(!yx>1O12d1o0XR``sDX*+7w3z-KX-l@B7_e#Fs)(GK7g$9zyVHXE`t~9 z3wFOPzI_~S08kIt2B2bNB+U%W>O2|;7R+yWx9xncJhFWn2Y`ytAZzBCW3YgsxsGYq zZM*HY$o4G&+RtTxtl0qW*xz@)jXHKTWJi<1Xa)loU8BihG#L!WWbh&U|DTBsEGic~ z4qPzWf~cm&fHfvJ1E+_=-MrKDC!K+S<12Y%bKW;s@e#(KX`unVXx{Yp3ZPOMWh1aedBmx>l6GrVB4Y$#BFq(gO z3`WZXiGReiG+Hl=mIt6t!)Q7fO$UP`9sB_fkpKUmb#sO< za4`H3XfXWkEyq3;a{=Z9|NbwpPXETt)OLc|n7PfLSyXCG!BUN%pMU;xX99MQ-I?y6 zfBrgN5;4U6=jws;WtZ%QCN!{E3H^B8e$L8y61-de;Ccho8wLj^p%tD79vJOF^wEWw zxeCr++yA%?)E7@-I(htD)M11+2ga}lRfWb`sC{$=U?2T@&R_NSS8bx1WI0vjt+RQ( z5u@;|5scFsSh9o+w(#h}MH`PaFvV>C`hLg4&)TX6GaWu{MC;sxI`9kB7@bdFNP>6y zJ%FR@rqTaTR-2xm2J|s0jD67lJKbmkp$KVa44XRR6s(Z{!`r9 z&8inBlH|BPX{-G~Op{3ph538JKj(0ksF32g(I^5X)X^v!%|#8+vSc(DflA@gf^M`f zl7Lo}qjk|}bAfHNMF(o^jkf53ZT!(jH>m$H+FSs21EHO^(dGi4=0fBA*!2P_@L6i; zsNsE3*ZIL~`!9e0FRVU(&k$*;*8l(O-31)rol8i!`bPc%-VM?T=Ga%2S)aXKKkK<{ z^>M@+Fnv5L%l=t$ekxzyicrk+#vIRzF~85>=0B@McI1K6c$T>B_iOrdH&YSGN56UT zEM2?2=kM~$dmGCU3)?;z;c?9R$qM!5Q77Q@^al>q;qmD^ll=dg^UB}IB39V#0rvlK zt)u((TIIz3xnhVl1qK^{5ruOx-)OMoTDmwI>^K%`j;3}T%Th-R85}EyM+=z|UC8`r YIOu*z{y@s-y`VMkp00i_>zopr0KzicBLDyZ literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9064f337045037ba70a7fc6fdc89d968e4c12dba GIT binary patch literal 11609 zcmeAS@N?(olHy`uVBq!ia0y~yU_QXW!1#cJ4JeZJl%)koF%}28J29*~C-V}>;Vkfo zEM{O(v;bj7*J*|cKtY*I7yl3-%>=|C@BxT5pfr#zw!8Yyzga-K-P6S}q=NCyO-C+g zMFG}>JO3}`{m++wae`8c{@hb5D&D{QnRS4Hna2P^INUy9E6*w-A(HX`B5%@uez*h! zb93^3?k!AQHLN@#yb=iwjBF5Mg>(UHm_wr{| z1TM(P_KGd0K{OyC=)i{6{MN6Nr@+ifNGSU9{nzparnXMrR=8k8<1R+=1Xht5A_i|> z9X|IRp!1{8u(J`{z18bEQXF_b+uuP6;(VKI7(Ym{ zurVSF>qrDNh$gVkfRAZ`44GlDfT7uru{Lq`Q}bK5j1UV;3Z!wXzN_};Udu^$J4Cg} z%_fonT*Z+FA3Oz5!SiSwSm5sveq3C-l15HuE`t}s7sR(k)-7JEi{#DicvR;edgnW%=E-4rPhmrX1JGpA1f*^VaDMPm z0~60LmM^Wj)9zXO+Ts)g0$e?nK~05y#U_h@h87)j8mFsBBWaza_Y8cM=ACjL}c8M1_uFT-+>gTe~ HDWM4f^iQs7 literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e634d8e09018ec9def9253f3d9d92d4070af6f82 GIT binary patch literal 11738 zcmeAS@N?(olHy`uVBq!ia0y~yU_QXW!1#cJ4JeZJl%)koF%}28J29*~C-V}>;Vkfo zEM{O(v;bj7*J*|cKtY*I7yl3-%>=|C@BxT5pfr#zF1~lUf&>GD*kex@$B+ufH@8mb zrWgt^A2?~BS)Y_4w<7W2jn~aSSGKvFoIn5k^W*lC1_v0Jc@RX+?#A=m|2Ngy|L>Gc zXkcWMfD`|CH4elb_{)l-+`u5wfsw72X_vIUc^#551`8Op4{#YEn+#Wa+irX9sM668 z7!85Z5Eu=C(GVC70X!jafSK(d-@7^$g~n>8JjOdLhKTC=LY~9lsSPYjoDyYk51;!b zkqWP_J7oU8U!T5Dq4Bz~flrPGlJQ%l0~%Bn8ajb^NhCHm`96((V}3qC>SjYfSq4RQSe~i0e#@8_y7M~>rU_ihr2UC z!`*Lh8WtTk5MXxr`~UK$zm2N{5_;zPRB_#u;rvuN|M^#KW_Zt)k!=^R&3buYuXcjN zcl%wAZ{8n9>byRMotMeGZCa%xCNY35Srki!gzRH?TtwJ#fXuLiHrANx99XAWsG3& zKhM!9z*|p@MgeHN314GkG#7xfIKCF=Xh8%jW$_MHjuu3~a(uKP8m*2;tK-pJFq#WS zbHUKh1)z50|NIBl6TkeIe<}U97cp-N?kBrOb|et&OC6S2{;GJ7}kKIw2_mU z%ix9Z1@XMiHH)L8k-9>8z|JDm8U|x{7Yk&TFmUSig8G8poV)W6JyDj2D{o}Qqgww? z+E2Ib+Yo&zo;yHefNn`cbRB^#H6D!v3;Z3*h0E@@oOHKCDCfqbI)2C5PrZ4$NPgM@ z?7{(Eeg@w61bM(mBA~%>e#1MpH~Tmz_tzl0lwv?jajD){F#DALmZ;6%@LSEt z?h~S~9f4;-+pj~p)ACEQPa{I$K&}HY;zbkS@dffg!l4Exo?k2_=84~ZXVg4F3^;5^ zz^(dA>usI;FRo2Pgh1o%24FJLK7fcXAnQO2Bdf$0&KG%y-pw}nd7>SzJmDZ7)!f@7 z_g!483m=wXVBU@=$=+?bYo7RNB0pUDXaXNi;E0?(n!ra(@L^wqA7H=w?T~!tPTQZr P!Dj|fS3j3^P6;Vkfo zEM{O(v;bj7*J*|cKtY*I7yl3-%>=|C@BxT5pfr#znte^Fz86TFd%8G=R4~4|b$YFg zClABHkN01G-`HrgL5=xP9J{L0wq29godfkR3=S|bLkWcj)(s44C}u-dZmZo^JE{^A zRHLCZnnIwtY&3Vg7%dq_%TG`RGFmE*mWrdLBCKUKS}Kl~ile3CXm0|kmp0l~B-B={ zIB?*8_ilT&1g6iNH<)g)7$VA$g1ZfWOc{kEW;UFD_bc^zO^*>=Zq1%w=l9S1$tqk? z%cLjFFM<^0>!bw^08P^tF1Q)H|IM8KK)77v)bRh;_usYL&v{1ufzd~YL`3ENU>74} z4wKpjBgW}>zn(t#Qz8{E7g70je!cByZnY1;SYp)VG?044G3E*lz6V&s)E;cwU3b$` zelbE$d;P!l^}CDfglG64NPX0J2;SX3aG;bK=uMx5R3^RMucy!bYv2y-i9 zFre`@8_NdH83#_W#FSmvw|<^H1umEH^lJUTuV?gU9C$5UFtcI-(trRk*cr@l2K)Yh zZ_oYoO|WB}-pS4d8$$rb%XMCk1Yv{5shm6Btcx!@cU%K5ci`0O|9@W3j5lb!PFk?n z|Gho;^XvmPq{Z;h>&E*NnAVdP?Eimlw|;Kk_>;64{=7cD?jTDXX~F*gYkv8;d|+xP zDTbfNpa0XuxrfAHe|`Vmock=#NQ>doj0MdlqZtdO=o~y5tA=Sma3uBrfAbd~r!p{z zwSb0D-`;fOa#j>zJ-GA#Qr`c3`4=ZBrRdK+wW8wvyPsL`dc)v=!|emM@~k2fA{qZL z@+R%)hZj=}%+1OBxwkNJ)v)q}@FEqxE2Ilp!yFnt84s_sd$R_)J~?^uKKBA9E(tX= zaH*``3oe$Q6N_d;R))E{%j4H;`)%pz|4VI{)?j zQRk0_KBy@%ns|VLFq(BC<=$w?18f3}7MzeSM#5;dC6O>%>q0ujjled~Xrp1Y$p+~e zj5ZoZ8x4?h0a#y-HX2474bYJjiGzW1 dc+OgP_1hu&^ZSk70|%xVJYD@<);T3K0RXgVDjWa+ literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9f88fcc02d9e2d74fdeb23bcf8b4e834fb0183e1 GIT binary patch literal 11827 zcmeAS@N?(olHy`uVBq!ia0y~yU_QXW!1#cJ4JeZJl%)koF%}28J29*~C-V}>;Vkfo zEM{O(v;bj7*J*|cKtY*I7yl3-%>=|C@BxT5pfr#zTBz;N_8myudb&7Fa7=RNrR_P@h_yZ?g5 zC=xt>qy-M_Yxr%?Ad%3($Oa=CTNoL6s+e~5&hM2+GKPmEfl;SH5}V50`MIMip+Pko zN~0+Rl9^!nXf$^q%A?WTF`7F@bH`}Oz_e?$R2(f8L9Nlz8ez0X7_AXTYXr<1;m_0g z_G$@CY8wn0+ow5q!#k)Ck{lSK8D=zap7D9`X+!ba!;|1r4h-k_{K~IcSUg?rLlG07 zZo3$~1AE|T1B2KBpn1l^J8a&>yxx!k@A3*9Fkb&pfB)*AxxzPQG&rALcog1!E-+MR zVBNqujfJ$~!!Ryv6OFUyBBtN$Mpw<^zM(pP_Qp(w);-notem1;RmY6ixQrw^ao z%I6L5TQf4+e17%+)9zXK%^G_-Ew;!+A^Pd!%uEpsvq!xJin7tz8cl?wc?(jmjTRY{ z7Vtk<85sWmFK20zXJC*>2MwgYz3JG+Y$(8T@aO;K$G?fkd{I<1sJ^1m<*+o)_WWyg zMoy0f6A%2hS#K|iXr=$jeo#I4%j5eba{p%IC+CAk!D%0u2^tGE16`TQs zbc3owqYsmpcP65i(qZE{Fmv_)r@Lq6djox2bR%*#QuW4jfGq*+ol8MTb=0VL4vfam zXkz0T%{$DaMZsuMU@%$~j1~n9qea1i(V}3qC}18f3Py_p;Lz1*2Vt~TFj^Fh76qe4 t0dORLv?v%Y3Py{9(V}3a6$L*S4!R$bf7`He7jP{%gQu&X%Q~loCIFuRMyvn; literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..c2bf62b0786395a78fa42272875d4077801e4be0 GIT binary patch literal 12389 zcmeHNdrTBZ7@yr+F7EY+&G}kHjM$6N|k~Hl|8jI zzUV26N<2B57@DAP6?_#cTidEg;V#9Zwknra0ShV-q=LeB7I6341d{us=|6MHKJMmb z_ct@&eDnLh-|UOgN4UzS$^Zbak-G3$03<8`n0=fS{*wBb*b6V%w%CXTpuBO~6ZnNp z*TroEz+*0dV2cX^Y{M0)|l8 zboQ1#jX|DuZ;RAj0W|0x4@jM|fcZT(VYmWc>i{N6Z~e1ndr4&!nc!uamf8G4l$4?w zZ0IDhU@LLOO_jOo=;V>Ns9AO`3r=0>UwyT#?;cX8XaV8Xzn0afE+bichE8lNe*%a$Q2-0fLsA` z1t@$&(I^V8QLX@Ga!_Il<=If$5JO2_l%u9zLG6L#dUsc80hsbJFFHK^H7wuVUruN_ zuBmbJd?oE3GCOYER?T{9-m#MSTW#GhBXEUL8-cf2+d3-bf<_=6OtmKmKly@CDGm9= zVE>nujYcuG|0>W7f`O4CQWfgU@(%@R!SDlvCse+Cez~N3rl*-&%*7K^$^f zi9w+Uj%$_N@89EET(hG4fuddKOn2wra5b%d-%#h&xJExL>)T9bsGRBU+CTCdD~_`3 zof=o~=fCW@LF$(wMbBbr8N zHDX3s23n2y#UHIkh}21`5f1%-lRDO#xNMw8*v&J{i0^LEVws@p<@lXkXomG}zy^W& z({_$qMqq@%GlyumVL*BxRAZTvpM;G@Jh4BeHiJF8@Nb%G21>I}f1NCrc4>G@EmI3I z179!w8iULG$@Yo@WpS{d7=zGsEe1L6az@;A1YsH`NGH;^Xl+)}C2qDgp!c9yng~l^ z1qaj+zaFynuuyE^Q^ligrJsp3UEVoo3@rNY-s0Bm>!HN-@W5ml~IUA7}ztTV|kGBaIh)lAN{-CjgPooPKZx{cXQWhG3fx&b0^YhHBA;{ zCbgwy3@pJ7zvULSx#e6Jk;Vkfo zEM{O(v;bj7*J*|cKtY*I7yl3-%>=|Cumy-Upfr#z)O*3xVIPo=^mK6ysbG9_)3J-$ zP=Mv&&;QGhe-n@SqNr$4eMO#0c) z^*~Jr7;+e2PYY&-{MuKxdY_pE$xpl^$AM6TA6gt-hT$Cd#0&ZVHJQSXe#&S+vA%{!w- z!DvA}TJMZjqrgVaXi+d)6pR)Hqea1JQ83zl8|{sbcCJVGSV1E{aIES7|2<_KM}dP( zVW2^#x1&Q$JflNQqXU4WSjYMvH>cqF}Tr08K=X sb`VB82%{Z@(N@7|Q9y99P$PeNmf-xq`y!76hng5XUHx3vIVCg!0Kh?)9{>OV literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6796058c28ee05319977f7227dde29bfc0889eb1 GIT binary patch literal 3946 zcmeAS@N?(olHy`uVBq!ia0y~yVAKKP2OMlb5&7_dT|kPlILO_JVcj{Imp~3@fk$L9 z1B0Rk2s64)GfV&q%4E9uhX83NAO?XCK&%0!fo!%*tOcg#Kzg31i(^OydsSvUlCNa`@LaHOypx$fm=WMbhF0}@6|GZ*b^ zWng4t>jn~%jXr_*of;Szn_U|i8had;t;kn&XlOX7-2 zsi_sHB!we|ZEG~p6vl&2KqW>jM$NZ$ITRWi5)^?-B$;M9z7+$S>97H05l`cp1!deo zGZi9$N*vl8(gJp~0?ibFTYGoZ+R;EBDM{-6yPwGi82LnGe(>w?w=%L@TqtnZz;e6w zY-0~|lk2sfHR~1}6Wvmyeo#o~;3J1)j0csn-L5@-_U-MluWAuZsu40LEEFPA&YpP1 zl@;T7x*VuVNQW;)MnGp%T1sqQ-u=9oe4whPqoc-+hTUjF8O;?Wmngp&{4DP*oDf>I R8`z>?@O1TaS?83{1ORmP_*nn| literal 0 HcmV?d00001 diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..d4a15f979b1619e2d08dcc2c4c3280395ee0f062 GIT binary patch literal 2696 zcmeAS@N?(olHy`uVBq!ia0y~yVAKKP3=TG+$lEQ)_<wAm z5MVO=GyC3U!<}r*OZad2aR?{~2zFdCSJ66I(ZskZkk`yzkV&z}W2Cz|h#^uxv%XqC-Q&K_!O<2RDV_E87JW91bK1DmW-8 zPtbf74KzGq1CW>?ctYf>F3<*p2q1BSBc-Sx z+W-s1|NqaQa9sy134eo1!ndR4Af%KZO>I<8ZKGA@XoFyIHg|yK;60J0mE3*|TY=>v NgQu&X%Q~loCIFws(cu69 literal 0 HcmV?d00001