diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index aee3b1867a..3203623ff8 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -447,13 +447,13 @@ 058D09D7195D050800B7D73C /* ASControlNode+Subclasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASControlNode+Subclasses.h"; sourceTree = ""; }; 058D09D8195D050800B7D73C /* ASDisplayNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASDisplayNode.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 058D09D9195D050800B7D73C /* ASDisplayNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDisplayNode.mm; sourceTree = ""; }; - 058D09DA195D050800B7D73C /* ASDisplayNode+Subclasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "ASDisplayNode+Subclasses.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 058D09DA195D050800B7D73C /* ASDisplayNode+Subclasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "ASDisplayNode+Subclasses.h"; sourceTree = ""; }; 058D09DB195D050800B7D73C /* ASDisplayNodeExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayNodeExtras.h; sourceTree = ""; }; 058D09DC195D050800B7D73C /* ASDisplayNodeExtras.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeExtras.mm; sourceTree = ""; }; 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 = ""; }; @@ -687,7 +687,9 @@ 058D09AD195D04C000B7D73C /* Products */, FD40E2760492F0CAAEAD552D /* Pods */, ); + indentWidth = 2; sourceTree = ""; + tabWidth = 2; }; 058D09AD195D04C000B7D73C /* Products */ = { isa = PBXGroup; diff --git a/AsyncDisplayKit/ASCellNode.m b/AsyncDisplayKit/ASCellNode.m index 4273a10cc1..14b304086b 100644 --- a/AsyncDisplayKit/ASCellNode.m +++ b/AsyncDisplayKit/ASCellNode.m @@ -111,7 +111,7 @@ static const CGFloat kFontSize = 18.0f; static const CGFloat kHorizontalPadding = 15.0f; static const CGFloat kVerticalPadding = 11.0f; UIEdgeInsets insets = UIEdgeInsetsMake(kVerticalPadding, kHorizontalPadding, kVerticalPadding, kHorizontalPadding); - return [ASInsetLayoutSpec newWithInsets:insets child:_textNode]; + return [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:_textNode]; } - (void)setText:(NSString *)text diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index c02c053e25..ab1a644091 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1333,12 +1333,13 @@ static NSInteger incrementIfFound(NSInteger i) { { ASDisplayNodeAssertThreadAffinity(self); if (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) { - id layoutSpec = [self layoutSpecThatFits:constrainedSize]; + ASLayoutSpec *layoutSpec = [self layoutSpecThatFits:constrainedSize]; + layoutSpec.isMutable = NO; ASLayout *layout = [layoutSpec measureWithSizeRange:constrainedSize]; // Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct. if (layout.layoutableObject != self) { layout.position = CGPointZero; - layout = [ASLayout newWithLayoutableObject:self size:layout.size sublayouts:@[layout]]; + layout = [ASLayout layoutWithLayoutableObject:self size:layout.size sublayouts:@[layout]]; } return [layout flattenedLayoutUsingPredicateBlock:^BOOL(ASLayout *evaluatedLayout) { return [_subnodes containsObject:evaluatedLayout.layoutableObject]; @@ -1347,7 +1348,7 @@ static NSInteger incrementIfFound(NSInteger i) { // If neither -layoutSpecThatFits: nor -calculateSizeThatFits: is overridden by subclassses, preferredFrameSize should be used, // assume that the default implementation of -calculateSizeThatFits: returns it. CGSize size = [self calculateSizeThatFits:constrainedSize.max]; - return [ASLayout newWithLayoutableObject:self size:ASSizeRangeClamp(constrainedSize, size)]; + return [ASLayout layoutWithLayoutableObject:self size:ASSizeRangeClamp(constrainedSize, size)]; } } diff --git a/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.h b/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.h index 508f7c8b28..ecc2e48473 100644 --- a/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.h @@ -15,11 +15,14 @@ */ @interface ASBackgroundLayoutSpec : ASLayoutSpec +@property (nonatomic, strong) id child; +@property (nonatomic, strong) id background; + /** @param child A child that is laid out to determine the size of this spec. If this is nil, then this method returns nil. @param background A layoutable object that is laid out behind the child. May be nil, in which case the background is omitted. */ -+ (instancetype)newWithChild:(id)child background:(id)background; ++ (instancetype)backgroundLayoutSpecWithChild:(id)child background:(id)background; @end diff --git a/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm b/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm index ae03e78836..e23ebaf903 100644 --- a/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm @@ -23,20 +23,21 @@ @implementation ASBackgroundLayoutSpec -+ (instancetype)newWithChild:(id)child background:(id)background +- (instancetype)initWithChild:(id)child background:(id)background { - if (child == nil) { - return nil; + self = [super init]; + if (self) { + ASDisplayNodeAssertNotNil(child, @"Child cannot be nil"); + _child = child; + _background = background; } - ASBackgroundLayoutSpec *spec = [super new]; - spec->_child = child; - spec->_background = background; - return spec; + return self; } -+ (instancetype)new + ++ (instancetype)backgroundLayoutSpecWithChild:(id)child background:(id)background; { - ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER(); + return [[self alloc] initWithChild:child background:background]; } /** @@ -56,7 +57,19 @@ contentsLayout.position = CGPointZero; [sublayouts addObject:contentsLayout]; - return [ASLayout newWithLayoutableObject:self size:contentsLayout.size sublayouts:sublayouts]; + return [ASLayout layoutWithLayoutableObject:self size:contentsLayout.size sublayouts:sublayouts]; +} + +- (void)setBackground:(id)background +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _background = background; +} + +- (void)setChild:(id)child +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _child = child; } @end diff --git a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h index 84e015ac57..dc50b265e7 100644 --- a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h @@ -37,6 +37,10 @@ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecSizingOptions) { /** Lays out a single layoutable child and position it so that it is centered into the layout bounds. */ @interface ASCenterLayoutSpec : ASLayoutSpec +@property (nonatomic, assign) ASCenterLayoutSpecCenteringOptions centeringOptions; +@property (nonatomic, assign) ASCenterLayoutSpecSizingOptions sizingOptions; +@property (nonatomic, strong) id child; + /** * Initializer. * @@ -46,8 +50,8 @@ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecSizingOptions) { * * @param child The child to center. */ -+ (instancetype)newWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions - sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions - child:(id)child; ++ (instancetype)centerLayoutSpecWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions + sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions + child:(id)child; @end diff --git a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm index f96b359172..fd52637480 100644 --- a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm @@ -20,22 +20,43 @@ id _child; } -+ (instancetype)newWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions - sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions - child:(id)child +- (instancetype)initWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions + sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions + child:(id)child; { - ASCenterLayoutSpec *spec = [super new]; - if (spec) { - spec->_centeringOptions = centeringOptions; - spec->_sizingOptions = sizingOptions; - spec->_child = child; + self = [super init]; + if (self) { + ASDisplayNodeAssertNotNil(child, @"Child cannot be nil"); + _centeringOptions = centeringOptions; + _sizingOptions = sizingOptions; + _child = child; } - return spec; + return self; } -+ (instancetype)new ++ (instancetype)centerLayoutSpecWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions + sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions + child:(id)child { - ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER(); + return [[self alloc] initWithCenteringOptions:centeringOptions sizingOptions:sizingOptions child:child]; +} + +- (void)setChild:(id)child +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _child = child; +} + +- (void)setCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _centeringOptions = centeringOptions; +} + +- (void)setSizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _sizingOptions = sizingOptions; } - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize @@ -73,7 +94,7 @@ ASRoundPixelValue(shouldCenterAlongY ? (size.height - sublayout.size.height) * 0.5f : 0) }; - return [ASLayout newWithLayoutableObject:self size:size sublayouts:@[sublayout]]; + return [ASLayout layoutWithLayoutableObject:self size:size sublayouts:@[sublayout]]; } @end diff --git a/AsyncDisplayKit/Layout/ASInsetLayoutSpec.h b/AsyncDisplayKit/Layout/ASInsetLayoutSpec.h index 7f1b0c9c00..3b140dfcc7 100644 --- a/AsyncDisplayKit/Layout/ASInsetLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASInsetLayoutSpec.h @@ -29,10 +29,13 @@ */ @interface ASInsetLayoutSpec : ASLayoutSpec +@property (nonatomic, strong) id child; +@property (nonatomic, assign) UIEdgeInsets insets; + /** @param insets The amount of space to inset on each side. @param child The wrapped child to inset. If nil, this method returns nil. */ -+ (instancetype)newWithInsets:(UIEdgeInsets)insets child:(id)child; ++ (instancetype)insetLayoutSpecWithInsets:(UIEdgeInsets)insets child:(id)child; @end diff --git a/AsyncDisplayKit/Layout/ASInsetLayoutSpec.mm b/AsyncDisplayKit/Layout/ASInsetLayoutSpec.mm index 8db3975773..01c382b663 100644 --- a/AsyncDisplayKit/Layout/ASInsetLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASInsetLayoutSpec.mm @@ -43,22 +43,32 @@ static CGFloat centerInset(CGFloat outer, CGFloat inner) @implementation ASInsetLayoutSpec -+ (instancetype)newWithInsets:(UIEdgeInsets)insets child:(id)child +- (instancetype)initWithInsets:(UIEdgeInsets)insets child:(id)child; { - if (child == nil) { - return nil; + self = [super init]; + if (self) { + ASDisplayNodeAssertNotNil(child, @"Child cannot be nil"); + _insets = insets; + _child = child; } - ASInsetLayoutSpec *spec = [super new]; - if (spec) { - spec->_insets = insets; - spec->_child = child; - } - return spec; + return self; } -+ (instancetype)new ++ (instancetype)insetLayoutSpecWithInsets:(UIEdgeInsets)insets child:(id)child { - ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER(); + return [[self alloc] initWithInsets:insets child:child]; +} + +- (void)setChild:(id)child +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _child = child; +} + +- (void)setInsets:(UIEdgeInsets)insets +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _insets = insets; } /** @@ -103,7 +113,7 @@ static CGFloat centerInset(CGFloat outer, CGFloat inner) sublayout.position = CGPointMake(x, y); - return [ASLayout newWithLayoutableObject:self size:computedSize sublayouts:@[sublayout]]; + return [ASLayout layoutWithLayoutableObject:self size:computedSize sublayouts:@[sublayout]]; } @end diff --git a/AsyncDisplayKit/Layout/ASLayout.h b/AsyncDisplayKit/Layout/ASLayout.h index a3d32feddc..71892b5996 100644 --- a/AsyncDisplayKit/Layout/ASLayout.h +++ b/AsyncDisplayKit/Layout/ASLayout.h @@ -43,10 +43,10 @@ extern BOOL CGPointIsNull(CGPoint point); * * @param sublayouts Sublayouts belong to the new layout. */ -+ (instancetype)newWithLayoutableObject:(id)layoutableObject - size:(CGSize)size - position:(CGPoint)position - sublayouts:(NSArray *)sublayouts; ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + size:(CGSize)size + position:(CGPoint)position + sublayouts:(NSArray *)sublayouts; /** * Convenience initializer that has CGPointNull position. @@ -60,9 +60,9 @@ extern BOOL CGPointIsNull(CGPoint point); * * @param sublayouts Sublayouts belong to the new layout. */ -+ (instancetype)newWithLayoutableObject:(id)layoutableObject - size:(CGSize)size - sublayouts:(NSArray *)sublayouts; ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + size:(CGSize)size + sublayouts:(NSArray *)sublayouts; /** * Convenience that has CGPointNull position and no sublayouts. @@ -73,7 +73,7 @@ extern BOOL CGPointIsNull(CGPoint point); * * @param size The size of this layout. */ -+ (instancetype)newWithLayoutableObject:(id)layoutableObject size:(CGSize)size; ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject size:(CGSize)size; /** diff --git a/AsyncDisplayKit/Layout/ASLayout.mm b/AsyncDisplayKit/Layout/ASLayout.mm index 31dd8ebc27..6695a07bde 100644 --- a/AsyncDisplayKit/Layout/ASLayout.mm +++ b/AsyncDisplayKit/Layout/ASLayout.mm @@ -22,10 +22,10 @@ extern BOOL CGPointIsNull(CGPoint point) @implementation ASLayout -+ (instancetype)newWithLayoutableObject:(id)layoutableObject - size:(CGSize)size - position:(CGPoint)position - sublayouts:(NSArray *)sublayouts ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + size:(CGSize)size + position:(CGPoint)position + sublayouts:(NSArray *)sublayouts { ASDisplayNodeAssert(layoutableObject, @"layoutableObject is required."); for (ASLayout *sublayout in sublayouts) { @@ -42,16 +42,16 @@ extern BOOL CGPointIsNull(CGPoint point) return l; } -+ (instancetype)newWithLayoutableObject:(id)layoutableObject - size:(CGSize)size - sublayouts:(NSArray *)sublayouts ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + size:(CGSize)size + sublayouts:(NSArray *)sublayouts { - return [self newWithLayoutableObject:layoutableObject size:size position:CGPointNull sublayouts:sublayouts]; + return [self layoutWithLayoutableObject:layoutableObject size:size position:CGPointNull sublayouts:sublayouts]; } -+ (instancetype)newWithLayoutableObject:(id)layoutableObject size:(CGSize)size ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject size:(CGSize)size { - return [self newWithLayoutableObject:layoutableObject size:size sublayouts:nil]; + return [self layoutWithLayoutableObject:layoutableObject size:size sublayouts:nil]; } - (ASLayout *)flattenedLayoutUsingPredicateBlock:(BOOL (^)(ASLayout *))predicateBlock @@ -76,10 +76,10 @@ extern BOOL CGPointIsNull(CGPoint point) context.visited = YES; if (predicateBlock(context.layout)) { - [flattenedSublayouts addObject:[ASLayout newWithLayoutableObject:context.layout.layoutableObject - size:context.layout.size - position:context.absolutePosition - sublayouts:nil]]; + [flattenedSublayouts addObject:[ASLayout layoutWithLayoutableObject:context.layout.layoutableObject + size:context.layout.size + position:context.absolutePosition + sublayouts:nil]]; } for (ASLayout *sublayout in context.layout.sublayouts) { @@ -88,7 +88,7 @@ extern BOOL CGPointIsNull(CGPoint point) } } - return [ASLayout newWithLayoutableObject:_layoutableObject size:_size sublayouts:flattenedSublayouts]; + return [ASLayout layoutWithLayoutableObject:_layoutableObject size:_size sublayouts:flattenedSublayouts]; } @end diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.h b/AsyncDisplayKit/Layout/ASLayoutSpec.h index c2602824e7..8edb8d8477 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.h @@ -10,7 +10,16 @@ #import -/** A layout spec is an immutable object that describes a layout, loosely inspired by React. */ +/** A layout spec is an temporarly mutable object that describes a layout, loosely inspired by React. */ @interface ASLayoutSpec : NSObject +/** + Creation of a layout spec should only happen by a user in layoutSpecThatFits:. During that method, a + layout spec can be created and mutated. Once it is passed back to ASDK, the isMutable flag will be + set to NO and any further mutations will cause an assert. + */ +@property (nonatomic, assign) BOOL isMutable; + +- (instancetype)init; + @end diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 8b3efd6f4d..6d6ab903f4 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -25,20 +25,21 @@ @synthesize flexBasis = _flexBasis; @synthesize alignSelf = _alignSelf; -+ (instancetype)new +- (instancetype)init { - ASLayoutSpec *spec = [super new]; - if (spec) { - spec->_flexBasis = ASRelativeDimensionUnconstrained; + self = [super init]; + if (self) { + _flexBasis = ASRelativeDimensionUnconstrained; + _isMutable = YES; } - return spec; + return self; } #pragma mark - Layout - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { - return [ASLayout newWithLayoutableObject:self size:constrainedSize.min]; + return [ASLayout layoutWithLayoutableObject:self size:constrainedSize.min]; } @end diff --git a/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.h b/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.h index 846b0cece5..ec82fe00e6 100644 --- a/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.h @@ -15,6 +15,9 @@ */ @interface ASOverlayLayoutSpec : ASLayoutSpec -+ (instancetype)newWithChild:(id)child overlay:(id)overlay; +@property (nonatomic, strong) id child; +@property (nonatomic, strong) id overlay; + ++ (instancetype)overlayLayoutWithChild:(id)child overlay:(id)overlay; @end diff --git a/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm b/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm index b478f69971..c9d0edb80c 100644 --- a/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm @@ -20,20 +20,32 @@ id _child; } -+ (instancetype)newWithChild:(id)child overlay:(id)overlay +- (instancetype)initWithChild:(id)child overlay:(id)overlay { - ASOverlayLayoutSpec *spec = [super new]; - if (spec) { + self = [super init]; + if (self) { ASDisplayNodeAssertNotNil(child, @"Child that will be overlayed on shouldn't be nil"); - spec->_overlay = overlay; - spec->_child = child; + _overlay = overlay; + _child = child; } - return spec; + return self; } -+ (instancetype)new ++ (instancetype)overlayLayoutWithChild:(id)child overlay:(id)overlay { - ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER(); + return [[self alloc] initWithChild:child overlay:overlay]; +} + +- (void)setChild:(id)child +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _child = child; +} + +- (void)setOverlay:(id)overlay +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _overlay = overlay; } /** @@ -50,7 +62,7 @@ [sublayouts addObject:overlayLayout]; } - return [ASLayout newWithLayoutableObject:self size:contentsLayout.size sublayouts:sublayouts]; + return [ASLayout layoutWithLayoutableObject:self size:contentsLayout.size sublayouts:sublayouts]; } @end diff --git a/AsyncDisplayKit/Layout/ASRatioLayoutSpec.h b/AsyncDisplayKit/Layout/ASRatioLayoutSpec.h index 73be620d71..fd7f6d657b 100644 --- a/AsyncDisplayKit/Layout/ASRatioLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASRatioLayoutSpec.h @@ -31,6 +31,10 @@ **/ @interface ASRatioLayoutSpec : ASLayoutSpec -+ (instancetype)newWithRatio:(CGFloat)ratio child:(id)child; + +@property (nonatomic, strong) id child; +@property (nonatomic, assign) CGFloat ratio; + ++ (instancetype)ratioLayoutSpecWithRatio:(CGFloat)ratio child:(id)child; @end diff --git a/AsyncDisplayKit/Layout/ASRatioLayoutSpec.mm b/AsyncDisplayKit/Layout/ASRatioLayoutSpec.mm index 2e358b533f..c106844c44 100644 --- a/AsyncDisplayKit/Layout/ASRatioLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASRatioLayoutSpec.mm @@ -25,24 +25,33 @@ id _child; } -+ (instancetype)newWithRatio:(CGFloat)ratio child:(id)child ++ (instancetype)ratioLayoutSpecWithRatio:(CGFloat)ratio child:(id)child { - ASDisplayNodeAssert(ratio > 0, @"Ratio should be strictly positive, but received %f", ratio); - if (child == nil) { - return nil; - } - - ASRatioLayoutSpec *spec = [super new]; - if (spec) { - spec->_ratio = ratio; - spec->_child = child; - } - return spec; + return [[self alloc] initWithRatio:ratio child:child]; } -+ (instancetype)new +- (instancetype)initWithRatio:(CGFloat)ratio child:(id)child; { - ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER(); + self = [super init]; + if (self) { + ASDisplayNodeAssertNotNil(child, @"Child cannot be nil"); + ASDisplayNodeAssert(ratio > 0, @"Ratio should be strictly positive, but received %f", ratio); + _ratio = ratio; + _child = child; + } + return self; +} + +- (void)setChild:(id)child +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _child = child; +} + +- (void)setRatio:(CGFloat)ratio +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _ratio = ratio; } - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize @@ -70,7 +79,7 @@ const ASSizeRange childRange = (bestSize == sizeOptions.end()) ? constrainedSize : ASSizeRangeMake(*bestSize, *bestSize); ASLayout *sublayout = [_child measureWithSizeRange:childRange]; sublayout.position = CGPointZero; - return [ASLayout newWithLayoutableObject:self size:sublayout.size sublayouts:@[sublayout]]; + return [ASLayout layoutWithLayoutableObject:self size:sublayout.size sublayouts:@[sublayout]]; } @end diff --git a/AsyncDisplayKit/Layout/ASStackLayoutSpec.h b/AsyncDisplayKit/Layout/ASStackLayoutSpec.h index 29f20603c5..c39522a83f 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASStackLayoutSpec.h @@ -49,16 +49,6 @@ typedef NS_ENUM(NSUInteger, ASStackLayoutAlignItems) { ASStackLayoutAlignItemsStretch, }; -typedef struct { - /** Specifies the direction children are stacked in. */ - ASStackLayoutDirection direction; - /** The amount of space between each child. */ - CGFloat spacing; - /** How children are aligned if there are no flexible children. */ - ASStackLayoutJustifyContent justifyContent; - /** Orientation of children along cross axis */ - ASStackLayoutAlignItems alignItems; -} ASStackLayoutSpecStyle; /** A simple layout spec that stacks a list of children vertically or horizontally. @@ -83,10 +73,29 @@ typedef struct { */ @interface ASStackLayoutSpec : ASLayoutSpec +/** Specifies the direction children are stacked in. */ +@property (nonatomic, assign) ASStackLayoutDirection direction; +/** The amount of space between each child. */ +@property (nonatomic, assign) CGFloat spacing; +/** The amount of space between each child. */ +@property (nonatomic, assign) ASStackLayoutJustifyContent justifyContent; +/** Orientation of children along cross axis */ +@property (nonatomic, assign) ASStackLayoutAlignItems alignItems; + +- (instancetype)init; + /** @param style Specifies how children are laid out. @param children ASLayoutable children to be positioned. */ -+ (instancetype)newWithStyle:(ASStackLayoutSpecStyle)style children:(NSArray *)children; ++ (instancetype)satckLayoutSpecWithDirection:(ASStackLayoutDirection)direction + spacing:(CGFloat)spacing + contentJustification:(ASStackLayoutJustifyContent)justifyContent + itemAlignment:(ASStackLayoutAlignItems)alignItems + children:(NSArray *)children; + + +- (void)addChild:(id)child; +- (void)addChildren:(NSArray *)children; @end diff --git a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm index 75b699c55b..e712bd2d0b 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm @@ -23,37 +23,104 @@ @implementation ASStackLayoutSpec { - ASStackLayoutSpecStyle _style; std::vector> _children; } -+ (instancetype)newWithStyle:(ASStackLayoutSpecStyle)style children:(NSArray *)children +- (instancetype)init { - ASStackLayoutSpec *spec = [super new]; - if (spec) { - spec->_style = style; - spec->_children = std::vector>(); - for (id child in children) { - spec->_children.push_back(child); - } - } - return spec; + return [self initWithDirection:ASStackLayoutDirectionHorizontal + spacing:0.0 + contentJustification:ASStackLayoutJustifyContentStart + itemAlignment:ASStackLayoutAlignItemsStart + children:nil]; } -+ (instancetype)new ++ (instancetype)satckLayoutSpecWithDirection:(ASStackLayoutDirection)direction + spacing:(CGFloat)spacing + contentJustification:(ASStackLayoutJustifyContent)justifyContent + itemAlignment:(ASStackLayoutAlignItems)alignItems + children:(NSArray *)children { - ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER(); + return [[self alloc] initWithDirection:direction + spacing:spacing + contentJustification:justifyContent + itemAlignment:alignItems + children:children]; +} + +- (instancetype)initWithDirection:(ASStackLayoutDirection)direction + spacing:(CGFloat)spacing + contentJustification:(ASStackLayoutJustifyContent)justifyContent + itemAlignment:(ASStackLayoutAlignItems)alignItems + children:(NSArray *)children; +{ + self = [super init]; + if (self) { + _direction = direction; + _alignItems = alignItems; + _spacing = spacing; + _justifyContent = justifyContent; + + _children = std::vector>(); + for (id child in children) { + _children.push_back(child); + } + } + return self; +} + +- (void)addChild:(id)child +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _children.push_back(child); +} + +- (void)addChildren:(NSArray *)children +{ + for (id child in children) { + [self addChild:child]; + } +} + + +- (void)setDirection:(ASStackLayoutDirection)direction +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _direction = direction; +} + +- (void)setAlignItems:(ASStackLayoutAlignItems)alignItems +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _alignItems = alignItems; +} + +- (void)setJustifyContent:(ASStackLayoutJustifyContent)justifyContent +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _justifyContent = justifyContent; +} + +- (void)setSpacing:(CGFloat)spacing +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _spacing = spacing; } - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { - const auto unpositionedLayout = ASStackUnpositionedLayout::compute(_children, _style, constrainedSize); - const auto positionedLayout = ASStackPositionedLayout::compute(unpositionedLayout, _style, constrainedSize); - const CGSize finalSize = directionSize(_style.direction, unpositionedLayout.stackDimensionSum, positionedLayout.crossSize); + ASStackLayoutSpecStyle style = {.direction = _direction, + .spacing = _spacing, + .justifyContent = _justifyContent, + .alignItems = _alignItems + }; + const auto unpositionedLayout = ASStackUnpositionedLayout::compute(_children, style, constrainedSize); + const auto positionedLayout = ASStackPositionedLayout::compute(unpositionedLayout, style, constrainedSize); + const CGSize finalSize = directionSize(style.direction, unpositionedLayout.stackDimensionSum, positionedLayout.crossSize); NSArray *sublayouts = [NSArray arrayWithObjects:&positionedLayout.sublayouts[0] count:positionedLayout.sublayouts.size()]; - return [ASLayout newWithLayoutableObject:self - size:ASSizeRangeClamp(constrainedSize, finalSize) - sublayouts:sublayouts]; + return [ASLayout layoutWithLayoutableObject:self + size:ASSizeRangeClamp(constrainedSize, finalSize) + sublayouts:sublayouts]; } @end diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.h b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.h index 259c32c4d6..38ed2f06d6 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.h @@ -34,7 +34,7 @@ * * @param size The size range that this child's size is trstricted according to. */ -+ (instancetype)newWithPosition:(CGPoint)position layoutableObject:(id)layoutableObject size:(ASRelativeSizeRange)size; ++ (instancetype)staticLayoutChildWithPosition:(CGPoint)position layoutableObject:(id)layoutableObject size:(ASRelativeSizeRange)size; /** * Convenience initializer with default size is Unconstrained in both dimensions, which sets the child's min size to zero @@ -44,7 +44,7 @@ * * @param layoutableObject The backing ASLayoutable object of this child. */ -+ (instancetype)newWithPosition:(CGPoint)position layoutableObject:(id)layoutableObject; ++ (instancetype)staticLayoutChildWithPosition:(CGPoint)position layoutableObject:(id)layoutableObject; @end @@ -58,6 +58,8 @@ /** @param children Children to be positioned at fixed positions, each is of type ASStaticLayoutSpecChild. */ -+ (instancetype)newWithChildren:(NSArray *)children; ++ (instancetype)staticLayoutSpecWithChildren:(NSArray *)children; + +- (void)addChild:(ASStaticLayoutSpecChild *)child; @end diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm index daf0971e56..b0becb0093 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm @@ -16,9 +16,9 @@ @implementation ASStaticLayoutSpecChild -+ (instancetype)newWithPosition:(CGPoint)position layoutableObject:(id)layoutableObject size:(ASRelativeSizeRange)size ++ (instancetype)staticLayoutChildWithPosition:(CGPoint)position layoutableObject:(id)layoutableObject size:(ASRelativeSizeRange)size; { - ASStaticLayoutSpecChild *c = [super new]; + ASStaticLayoutSpecChild *c = [[super alloc] init]; if (c) { c->_position = position; c->_layoutableObject = layoutableObject; @@ -27,9 +27,9 @@ return c; } -+ (instancetype)newWithPosition:(CGPoint)position layoutableObject:(id)layoutableObject ++ (instancetype)staticLayoutChildWithPosition:(CGPoint)position layoutableObject:(id)layoutableObject { - return [self newWithPosition:position layoutableObject:layoutableObject size:ASRelativeSizeRangeUnconstrained]; + return [self staticLayoutChildWithPosition:position layoutableObject:layoutableObject size:ASRelativeSizeRangeUnconstrained]; } @end @@ -39,18 +39,24 @@ NSArray *_children; } -+ (instancetype)newWithChildren:(NSArray *)children ++ (instancetype)staticLayoutSpecWithChildren:(NSArray *)children { - ASStaticLayoutSpec *spec = [super new]; - if (spec) { - spec->_children = children; - } - return spec; + return [[self alloc] initWithChildren:children]; } -+ (instancetype)new +- (instancetype)initWithChildren:(NSArray *)children { - ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER(); + self = [super init]; + if (self) { + _children = children; + } + return self; +} + +- (void)addChild:(ASStaticLayoutSpecChild *)child +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _children = [_children arrayByAddingObject:child]; } - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize @@ -88,9 +94,9 @@ } } - return [ASLayout newWithLayoutableObject:self - size:ASSizeRangeClamp(constrainedSize, size) - sublayouts:sublayouts]; + return [ASLayout layoutWithLayoutableObject:self + size:ASSizeRangeClamp(constrainedSize, size) + sublayouts:sublayouts]; } @end diff --git a/AsyncDisplayKit/Private/ASStackLayoutSpecUtilities.h b/AsyncDisplayKit/Private/ASStackLayoutSpecUtilities.h index 4f5eff0aeb..33895b9bd5 100644 --- a/AsyncDisplayKit/Private/ASStackLayoutSpecUtilities.h +++ b/AsyncDisplayKit/Private/ASStackLayoutSpecUtilities.h @@ -10,6 +10,13 @@ #import "ASStackLayoutSpec.h" +typedef struct { + ASStackLayoutDirection direction; + CGFloat spacing; + ASStackLayoutJustifyContent justifyContent; + ASStackLayoutAlignItems alignItems; +} ASStackLayoutSpecStyle; + inline CGFloat stackDimension(const ASStackLayoutDirection direction, const CGSize size) { return (direction == ASStackLayoutDirectionVertical) ? size.height : size.width; diff --git a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.h b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.h index 45f648192e..4112af8e66 100644 --- a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.h +++ b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.h @@ -11,6 +11,7 @@ #import #import "ASLayout.h" +#import "ASStackLayoutSpecUtilities.h" #import "ASStackLayoutSpec.h" struct ASStackUnpositionedItem { diff --git a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm index 9eb83a5b0d..6e275c82c0 100644 --- a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm @@ -297,7 +297,7 @@ static std::vector layoutChildrenAlongUnconstrainedStac const CGFloat exactStackDimension = ASRelativeDimensionResolve(child.flexBasis, stackDimension(style.direction, size)); if (useOptimizedFlexing && isFlexibleInBothDirections(child)) { - return { child, [ASLayout newWithLayoutableObject:child size:{0, 0}] }; + return { child, [ASLayout layoutWithLayoutableObject:child size:{0, 0}] }; } else { return { child, diff --git a/examples/Kittens/Sample.xcodeproj/project.pbxproj b/examples/Kittens/Sample.xcodeproj/project.pbxproj index 293b513d1e..1e08bbe8c1 100644 --- a/examples/Kittens/Sample.xcodeproj/project.pbxproj +++ b/examples/Kittens/Sample.xcodeproj/project.pbxproj @@ -58,7 +58,9 @@ 1A943BF0259746F18D6E423F /* Frameworks */, 1AE410B73DA5C3BD087ACDD7 /* Pods */, ); + indentWidth = 2; sourceTree = ""; + tabWidth = 2; }; 05E2128219D4DB510098F589 /* Products */ = { isa = PBXGroup; diff --git a/examples/Kittens/Sample/BlurbNode.m b/examples/Kittens/Sample/BlurbNode.m index 1c646a25ad..a4802daf5c 100644 --- a/examples/Kittens/Sample/BlurbNode.m +++ b/examples/Kittens/Sample/BlurbNode.m @@ -76,14 +76,14 @@ static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName"; #if UseAutomaticLayout - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - return - [ASInsetLayoutSpec - newWithInsets:UIEdgeInsetsMake(kTextPadding, kTextPadding, kTextPadding, kTextPadding) - child: - [ASCenterLayoutSpec - newWithCenteringOptions:ASCenterLayoutSpecCenteringX // Center the text horizontally - sizingOptions:ASCenterLayoutSpecSizingOptionMinimumY // Takes up minimum height - child:_textNode]]; + ASCenterLayoutSpec *centerSpec = [[ASCenterLayoutSpec alloc] init]; + centerSpec.centeringOptions = ASCenterLayoutSpecCenteringX; + centerSpec.sizingOptions = ASCenterLayoutSpecSizingOptionMinimumY; + centerSpec.child = _textNode; + + + return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(kTextPadding, kTextPadding, kTextPadding, kTextPadding) + child:centerSpec]; } #else - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index a852bcb801..faf2cc9693 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -137,16 +137,16 @@ static const CGFloat kInnerPadding = 10.0f; _imageNode.preferredFrameSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); _textNode.flexShrink = YES; - return - [ASInsetLayoutSpec - newWithInsets:UIEdgeInsetsMake(kOuterPadding, kOuterPadding, kOuterPadding, kOuterPadding) - child: - [ASStackLayoutSpec - newWithStyle:{ - .direction = ASStackLayoutDirectionHorizontal, - .spacing = kInnerPadding - } - children:!_swappedTextAndImage ? @[_imageNode, _textNode] : @[_textNode, _imageNode]]]; + ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; + stackSpec.direction = ASStackLayoutDirectionHorizontal; + stackSpec.spacing = kInnerPadding; + [stackSpec addChildren:!_swappedTextAndImage ? @[_imageNode, _textNode] : @[_textNode, _imageNode]]; + + ASInsetLayoutSpec *insetSpec = [[ASInsetLayoutSpec alloc] init]; + insetSpec.insets = UIEdgeInsetsMake(kOuterPadding, kOuterPadding, kOuterPadding, kOuterPadding); + insetSpec.child = stackSpec; + + return insetSpec; } // With box model, you don't need to override this method, unless you want to add custom logic.