diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 78394feb..fd6dab77 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -203,9 +203,6 @@ 69708BA61D76386D005C3CF9 /* ASEqualityHashHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 69708BA41D76386D005C3CF9 /* ASEqualityHashHelpers.h */; }; 69708BA71D76386D005C3CF9 /* ASEqualityHashHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69708BA51D76386D005C3CF9 /* ASEqualityHashHelpers.mm */; }; 69708BA81D76386D005C3CF9 /* ASEqualityHashHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69708BA51D76386D005C3CF9 /* ASEqualityHashHelpers.mm */; }; - 6959433E1D70815300B0EE1F /* ASDisplayNodeLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */; }; - 6959433F1D70815300B0EE1F /* ASDisplayNodeLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */; }; - 695943401D70815300B0EE1F /* ASDisplayNodeLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 6959433D1D70815300B0EE1F /* ASDisplayNodeLayout.h */; }; 697B315A1CFE4B410049936F /* ASEditableTextNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 697B31591CFE4B410049936F /* ASEditableTextNodeTests.m */; }; 697C0DE41CF38F28001DE0D4 /* ASLayoutValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 697C0DE11CF38F28001DE0D4 /* ASLayoutValidation.h */; }; 697C0DE51CF38F28001DE0D4 /* ASLayoutValidation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 697C0DE21CF38F28001DE0D4 /* ASLayoutValidation.mm */; }; @@ -972,8 +969,6 @@ 696FCB301D6E46050093471E /* ASBackgroundLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASBackgroundLayoutSpecSnapshotTests.mm; sourceTree = ""; }; 69708BA41D76386D005C3CF9 /* ASEqualityHashHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASEqualityHashHelpers.h; path = TextKit/ASEqualityHashHelpers.h; sourceTree = ""; }; 69708BA51D76386D005C3CF9 /* ASEqualityHashHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASEqualityHashHelpers.mm; path = TextKit/ASEqualityHashHelpers.mm; sourceTree = ""; }; - 6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeLayout.mm; sourceTree = ""; }; - 6959433D1D70815300B0EE1F /* ASDisplayNodeLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayNodeLayout.h; sourceTree = ""; }; 697B31591CFE4B410049936F /* ASEditableTextNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASEditableTextNodeTests.m; sourceTree = ""; }; 697C0DE11CF38F28001DE0D4 /* ASLayoutValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutValidation.h; path = AsyncDisplayKit/Layout/ASLayoutValidation.h; sourceTree = ""; }; 697C0DE21CF38F28001DE0D4 /* ASLayoutValidation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASLayoutValidation.mm; path = AsyncDisplayKit/Layout/ASLayoutValidation.mm; sourceTree = ""; }; @@ -1523,8 +1518,6 @@ 044285051BAA63FE00D16268 /* ASBatchFetching.h */, 044285061BAA63FE00D16268 /* ASBatchFetching.m */, 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */, - 8B0768B11CE752EC002E1453 /* ASDefaultPlaybackButton.h */, - 8B0768B21CE752EC002E1453 /* ASDefaultPlaybackButton.m */, AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */, AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */, 058D0A08195D050800B7D73C /* ASDisplayNode+AsyncDisplay.mm */, @@ -1533,8 +1526,6 @@ DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */, 058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */, 058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */, - 6959433D1D70815300B0EE1F /* ASDisplayNodeLayout.h */, - 6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */, 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */, 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */, 68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */, @@ -1560,6 +1551,8 @@ ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */, 83A7D9581D44542100BF333E /* ASWeakMap.h */, 83A7D9591D44542100BF333E /* ASWeakMap.m */, + 8B0768B11CE752EC002E1453 /* ASDefaultPlaybackButton.h */, + 8B0768B21CE752EC002E1453 /* ASDefaultPlaybackButton.m */, ); path = Private; sourceTree = ""; @@ -1815,7 +1808,6 @@ 697C0DE41CF38F28001DE0D4 /* ASLayoutValidation.h in Headers */, B35062211B010EFD0018CF92 /* ASLayoutRangeType.h in Headers */, 34EFC76A1B701CE600AD841F /* ASLayoutSpec.h in Headers */, - 695943401D70815300B0EE1F /* ASDisplayNodeLayout.h in Headers */, 34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */, B350625C1B010F070018CF92 /* ASLog.h in Headers */, 0442850E1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.h in Headers */, @@ -2195,7 +2187,6 @@ 68355B311CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */, 9CFFC6C01CCAC73C006A6476 /* ASViewController.mm in Sources */, 055F1A3519ABD3E3004DAFF1 /* ASTableView.mm in Sources */, - 6959433E1D70815300B0EE1F /* ASDisplayNodeLayout.mm in Sources */, 058D0A17195D050800B7D73C /* ASTextNode.mm in Sources */, 257754AC1BEE44CD00737CA5 /* ASTextKitRenderer.mm in Sources */, 8BDA5FC61CDBDDE1007D13B2 /* ASVideoPlayerNode.mm in Sources */, @@ -2377,7 +2368,6 @@ DB78412E1C6BCE1600A9E2B4 /* _ASTransitionContext.m in Sources */, B350620B1B010EFD0018CF92 /* ASTableView.mm in Sources */, B350620E1B010EFD0018CF92 /* ASTextNode.mm in Sources */, - 6959433F1D70815300B0EE1F /* ASDisplayNodeLayout.mm in Sources */, 68355B3E1CB57A60001D4E68 /* ASPINRemoteImageDownloader.m in Sources */, 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */, 254C6B871BF94F8A003EC431 /* ASTextKitEntityAttribute.m in Sources */, diff --git a/AsyncDisplayKit/ASButtonNode.mm b/AsyncDisplayKit/ASButtonNode.mm index 64e6ca5a..d00edf25 100644 --- a/AsyncDisplayKit/ASButtonNode.mm +++ b/AsyncDisplayKit/ASButtonNode.mm @@ -491,17 +491,10 @@ spec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:contentEdgeInsets child:spec]; } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" if (CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero) == NO) { -#if DEBUG - NSLog(@"Using -[ASDisplayNde preferredFrameSize] is deprecated."); -#endif - stack.width = ASDimensionMake(ASDimensionUnitPoints, self.preferredFrameSize.width); - stack.height = ASDimensionMake(ASDimensionUnitPoints, self.preferredFrameSize.height); + stack.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(self.preferredFrameSize); spec = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[stack]]; } -#pragma clang diagnostic pop if (_backgroundImageNode.image) { spec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:spec background:_backgroundImageNode]; diff --git a/AsyncDisplayKit/ASDisplayNode+Deprecated.h b/AsyncDisplayKit/ASDisplayNode+Deprecated.h index 737116d4..80c84a77 100644 --- a/AsyncDisplayKit/ASDisplayNode+Deprecated.h +++ b/AsyncDisplayKit/ASDisplayNode+Deprecated.h @@ -14,38 +14,6 @@ @interface ASDisplayNode (Deprecated) -/** - * @abstract Asks the node to measure and return the size that best fits its subnodes. - * - * @param constrainedSize The maximum size the receiver should fit in. - * - * @return A new size that fits the receiver's subviews. - * - * @discussion Though this method does not set the bounds of the view, it does have side effects--caching both the - * constraint and the result. - * - * @warning Subclasses must not override this; it calls -measureWithSizeRange: with zero min size. - * -measureWithSizeRange: caches results from -calculateLayoutThatFits:. Calling this method may - * be expensive if result is not cached. - * - * @see measureWithSizeRange: - * @see [ASDisplayNode(Subclassing) calculateLayoutThatFits:] - * - * @deprecated Deprecated in version 2.0: Use layoutThatFits: with a constrained size of (CGSizeZero, constrainedSize) and call size on the returned ASLayout - */ -- (CGSize)measure:(CGSize)constrainedSize ASDISPLAYNODE_DEPRECATED; - -/** - * @abstract Calculate a layout based on given size range. - * - * @param constrainedSize The minimum and maximum sizes the receiver should fit in. - * - * @return An ASLayout instance defining the layout of the receiver and its children. - * - * @deprecated Deprecated in version 2.0: Use ASCalculateRootLayout or ASCalculateLayout instead - */ -- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize ASDISPLAYNODE_DEPRECATED; - /** * @abstract Called whenever the visiblity of the node changed. * diff --git a/AsyncDisplayKit/ASDisplayNode+Subclasses.h b/AsyncDisplayKit/ASDisplayNode+Subclasses.h index cce25a4c..16932feb 100644 --- a/AsyncDisplayKit/ASDisplayNode+Subclasses.h +++ b/AsyncDisplayKit/ASDisplayNode+Subclasses.h @@ -118,19 +118,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize; -/** - * ASDisplayNode's implementation of -layoutThatFits:parentSize: calls this method to resolve the node's size - * against parentSize, intersect it with constrainedSize, and call -calculateLayoutThatFits: with the result. - * - * In certain advanced cases, you may want to customize this logic. Overriding this method allows you to receive all - * three parameters and do the computation yourself. - * - * @warning Overriding this method should be done VERY rarely. - */ -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - restrictedToSize:(ASLayoutableSize)size - relativeToParentSize:(CGSize)parentSize; - /** * @abstract Return the calculated size. * @@ -143,7 +130,7 @@ NS_ASSUME_NONNULL_BEGIN * * @note Subclasses that override are committed to manual layout. Therefore, -layout: must be overriden to layout all subnodes or subviews. * - * @note This method should not be called directly outside of ASDisplayNode; use -layoutThatFits: or layoutThatFits:parentSize: instead. + * @note This method should not be called directly outside of ASDisplayNode; use -measure: or -calculatedLayout instead. */ - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize; diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 98970da0..74ed9578 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -248,7 +248,26 @@ NS_ASSUME_NONNULL_BEGIN /** @name Managing dimensions */ /** - * @abstract Asks the node to return a layout based on given size range. + * @abstract Asks the node to measure and return the size that best fits its subnodes. + * + * @param constrainedSize The maximum size the receiver should fit in. + * + * @return A new size that fits the receiver's subviews. + * + * @discussion Though this method does not set the bounds of the view, it does have side effects--caching both the + * constraint and the result. + * + * @warning Subclasses must not override this; it calls -measureWithSizeRange: with zero min size. + * -measureWithSizeRange: caches results from -calculateLayoutThatFits:. Calling this method may + * be expensive if result is not cached. + * + * @see measureWithSizeRange: + * @see [ASDisplayNode(Subclassing) calculateLayoutThatFits:] + */ +- (CGSize)measure:(CGSize)constrainedSize; + +/** + * @abstract Asks the node to measure a layout based on given size range. * * @param constrainedSize The minimum and maximum sizes the receiver should fit in. * @@ -262,7 +281,8 @@ NS_ASSUME_NONNULL_BEGIN * * @see [ASDisplayNode(Subclassing) calculateLayoutThatFits:] */ -- (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize; +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize; + /** * @abstract Provides a way to declare a block to provide an ASLayoutSpec without having to subclass ASDisplayNode and @@ -297,6 +317,16 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, readonly, assign) ASSizeRange constrainedSizeForCalculatedLayout; +/** + * @abstract Provides a default intrinsic content size for calculateSizeThatFits:. This is useful when laying out + * a node that either has no intrinsic content size or should be laid out at a different size than its intrinsic content + * size. For example, this property could be set on an ASImageNode to display at a size different from the underlying + * image size. + * + * @return The preferred frame size of this node + */ +@property (nonatomic, assign, readwrite) CGSize preferredFrameSize; + /** @name Managing the nodes hierarchy */ @@ -595,6 +625,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Convenience methods for debugging. */ + @interface ASDisplayNode (Debugging) /** @@ -807,20 +838,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)cancelLayoutTransition; -#pragma mark - Deprecated - -/** - * @abstract Provides a default intrinsic content size for calculateSizeThatFits:. This is useful when laying out - * a node that either has no intrinsic content size or should be laid out at a different size than its intrinsic content - * size. For example, this property could be set on an ASImageNode to display at a size different from the underlying - * image size. - * - * @return The preferred frame size of this node - * - * @deprecated Deprecated in version 2.0: Use sizing properties instead: height, minHeight, maxHeight, width, minWidth, maxWidth - */ -@property (nonatomic, assign, readwrite) CGSize preferredFrameSize ASDISPLAYNODE_DEPRECATED; - @end /* diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 3f8604ff..40fa4c6c 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -26,7 +26,6 @@ #import "ASEqualityHelpers.h" #import "ASRunLoopQueue.h" #import "ASEnvironmentInternal.h" -#import "ASDimension.h" #import "ASInternalHelpers.h" #import "ASLayout.h" @@ -69,19 +68,14 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS @implementation ASDisplayNode -// Dynamic properties for ASLayoutables -@dynamic layoutableType, size; -// Dynamic properties for sizing -@dynamic width, height, minWidth, maxWidth, minHeight, maxHeight; -// Dynamic properties for stack spec -@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender; -// Dynamic properties for static spec -@dynamic layoutPosition; +// these dynamic properties all defined in ASLayoutOptionsPrivate.m +@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, + alignSelf, ascender, descender, sizeRange, layoutPosition, layoutableType; @synthesize name = _name; +@synthesize preferredFrameSize = _preferredFrameSize; @synthesize isFinalLayoutable = _isFinalLayoutable; @synthesize threadSafeBounds = _threadSafeBounds; -@synthesize layoutSpecBlock = _layoutSpecBlock; static BOOL suppressesInvalidCollectionUpdateExceptions = NO; @@ -198,16 +192,12 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) if (self != [ASDisplayNode class]) { // Subclasses should never override these - NSString *classString = NSStringFromClass(self); - - ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedSize)), @"Subclass %@ must not override calculatedSize method", classString); - ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedLayout)), @"Subclass %@ must not override calculatedLayout method", classString); - ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measure:)), @"Subclass %@ must not override measure: method", classString); - ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measureWithSizeRange:)), @"Subclass %@ must not override measureWithSizeRange: method. Instead overwrite calculateLayoutThatFits:", classString); - ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutThatFits:)), @"Subclass %@ must not override layoutThatFits: method", classString); - ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutThatFits:parentSize:)), @"Subclass %@ must not override layoutThatFits:parentSize method", classString); - ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearContents)), @"Subclass %@ must not override recursivelyClearContents method", classString); - ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearFetchedData)), @"Subclass %@ must not override recursivelyClearFetchedData method", classString); + ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedSize)), @"Subclass %@ must not override calculatedSize method", NSStringFromClass(self)); + ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedLayout)), @"Subclass %@ must not override calculatedLayout method", NSStringFromClass(self)); + ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measure:)), @"Subclass %@ must not override measure method", NSStringFromClass(self)); + ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measureWithSizeRange:)), @"Subclass %@ must not override measureWithSizeRange method", NSStringFromClass(self)); + ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearContents)), @"Subclass %@ must not override recursivelyClearContents method", NSStringFromClass(self)); + ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearFetchedData)), @"Subclass %@ must not override recursivelyClearFetchedData method", NSStringFromClass(self)); } // Below we are pre-calculating values per-class and dynamically adding a method (_staticInitialize) to populate these values @@ -304,12 +294,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) [self _staticInitialize]; _contentsScaleForDisplay = ASScreenScale(); _displaySentinel = [[ASSentinel alloc] init]; - - _size = ASLayoutableSizeMake(); _preferredFrameSize = CGSizeZero; - _environmentState = ASEnvironmentStateMakeDefault(); - _calculatedDisplayNodeLayout = std::make_shared(); + _environmentState = ASEnvironmentStateMakeDefault(); _defaultLayoutTransitionDuration = 0.2; _defaultLayoutTransitionDelay = 0.0; @@ -462,6 +449,11 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) return !(_hierarchyState & ASHierarchyStateRasterized); } +- (BOOL)__shouldSize +{ + return YES; +} + - (UIView *)_viewToLoad { UIView *view; @@ -647,72 +639,46 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) return _flags.layerBacked; } -#pragma mark - Layout measurement and sizing +#pragma mark - Layout measurement calculation -- (ASLayoutableSize)size +- (CGSize)measure:(CGSize)constrainedSize { - ASDN::MutexLocker l(__instanceLock__); - return _size; + return [self measureWithSizeRange:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; } -- (void)setSize:(ASLayoutableSize)size +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { ASDN::MutexLocker l(__instanceLock__); - if (ASLayoutableSizeEqualToLayoutableSize(_size, size) == NO) { - _size = size; - [self invalidateCalculatedLayout]; - } -} - -ASLayoutableSizeForwarding -ASLayoutableSizeHelperForwarding - -- (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize -{ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - return [self measureWithSizeRange:constrainedSize]; -#pragma clang diagnostic pop -} - -- (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize parentSize:(CGSize)parentSize -{ - ASDN::MutexLocker l(__instanceLock__); - - if ([self shouldCalculateLayoutWithConstrainedSize:constrainedSize parentSize:parentSize] == NO) { - ASDisplayNodeAssertNotNil(_calculatedDisplayNodeLayout->layout, @"-[ASDisplayNode layoutThatFits:parentSize:] _layout should not be nil! %@", self); - return _calculatedDisplayNodeLayout->layout ? : [ASLayout layoutWithLayoutable:self size:{0, 0}]; + if (! [self shouldMeasureWithSizeRange:constrainedSize]) { + ASDisplayNodeAssertNotNil(_calculatedLayout, @"-[ASDisplayNode measureWithSizeRange:] _layout should not be nil! %@", self); + return _calculatedLayout ? : [ASLayout layoutWithLayoutableObject:self constrainedSizeRange:constrainedSize size:CGSizeZero]; } [self cancelLayoutTransition]; + + ASLayout *previousLayout = _calculatedLayout; + ASLayout *newLayout = [self calculateLayoutThatFits:constrainedSize]; - // Prepare for layout transition - auto previousLayout = _calculatedDisplayNodeLayout; - auto pendingLayout = std::make_shared( - [self calculateLayoutThatFits:constrainedSize restrictedToSize:_size relativeToParentSize:parentSize], - constrainedSize, - parentSize - ); _pendingLayoutTransition = [[ASLayoutTransition alloc] initWithNode:self - pendingLayout:pendingLayout + pendingLayout:newLayout previousLayout:previousLayout]; - // Only complete the pending layout transition if the node is not a subnode of a node that is currently - // in a layout transition if (ASHierarchyStateIncludesLayoutPending(_hierarchyState) == NO) { // Complete the pending layout transition immediately [self _completePendingLayoutTransition]; } - ASDisplayNodeAssertNotNil(pendingLayout->layout, @"-[ASDisplayNode layoutThatFits:parentSize:] newLayout should not be nil! %@", self); - return pendingLayout->layout; + ASDisplayNodeAssertNotNil(newLayout, @"-[ASDisplayNode measureWithSizeRange:] newLayout should not be nil! %@", self); + return newLayout; } -- (BOOL)shouldCalculateLayoutWithConstrainedSize:(ASSizeRange)constrainedSize parentSize:(CGSize)parentSize +- (BOOL)shouldMeasureWithSizeRange:(ASSizeRange)constrainedSize { ASDN::MutexLocker l(__instanceLock__); - - // Don't remeasure if in layout pending state and a new transition already started + if (![self __shouldSize]) { + return NO; + } + if (ASHierarchyStateIncludesLayoutPending(_hierarchyState)) { ASLayoutableContext context = ASLayoutableGetCurrentContext(); if (ASLayoutableContextIsNull(context) || _pendingTransitionID != context.transitionID) { @@ -720,8 +686,15 @@ ASLayoutableSizeHelperForwarding } } - // Check if display node layout is still valid - return _calculatedDisplayNodeLayout->isValidForConstrainedSizeParentSize(constrainedSize, parentSize) == NO; + // Only generate a new layout if: + // - The current layout is dirty + // - The passed constrained size is different than the layout's constrained size + return ([self _hasDirtyLayout] || !ASSizeRangeEqualToSizeRange(constrainedSize, _calculatedLayout.constrainedSizeRange)); +} + +- (BOOL)_hasDirtyLayout +{ + return _calculatedLayout == nil || _calculatedLayout.isDirty; } - (ASLayoutableType)layoutableType @@ -754,14 +727,14 @@ ASLayoutableSizeHelperForwarding shouldMeasureAsync:(BOOL)shouldMeasureAsync measurementCompletion:(void(^)())completion { - if (_calculatedDisplayNodeLayout->layout == nil) { - // No measure pass happened before, it's not possible to reuse the constrained size for the transition - // Using CGSizeZero for the sizeRange can cause negative values in client layout code. + if (_calculatedLayout == nil) { + // constrainedSizeRange returns a struct and is invalid to call on nil. + // Defaulting to CGSizeZero can cause negative values in client layout code. return; } [self invalidateCalculatedLayout]; - [self transitionLayoutWithSizeRange:_calculatedDisplayNodeLayout->constrainedSize + [self transitionLayoutWithSizeRange:_calculatedLayout.constrainedSizeRange animated:animated shouldMeasureAsync:shouldMeasureAsync measurementCompletion:completion]; @@ -774,8 +747,7 @@ ASLayoutableSizeHelperForwarding measurementCompletion:(void(^)())completion { // Passed constrainedSize is the the same as the node's current constrained size it's a noop - ASDisplayNodeAssertMainThread(); - if ([self shouldCalculateLayoutWithConstrainedSize:constrainedSize parentSize:constrainedSize.max] == NO) { + if ([self shouldMeasureWithSizeRange:constrainedSize] == NO) { return; } @@ -786,7 +758,6 @@ ASLayoutableSizeHelperForwarding int32_t transitionID = [self _startNewTransition]; - // Move all subnodes in a pending state ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) { ASDisplayNodeAssert([node _isTransitionInProgress] == NO, @"Can't start a transition when one of the subnodes is performing one."); node.hierarchyState |= ASHierarchyStateLayoutPending; @@ -806,9 +777,7 @@ ASLayoutableSizeHelperForwarding ASDN::MutexLocker l(__instanceLock__); BOOL automaticallyManagesSubnodesDisabled = (self.automaticallyManagesSubnodes == NO); self.automaticallyManagesSubnodes = YES; // Temporary flag for 1.9.x - newLayout = [self calculateLayoutThatFits:constrainedSize - restrictedToSize:_size - relativeToParentSize:constrainedSize.max]; + newLayout = [self calculateLayoutThatFits:constrainedSize]; if (automaticallyManagesSubnodesDisabled) { self.automaticallyManagesSubnodes = NO; // Temporary flag for 1.9.x } @@ -828,17 +797,10 @@ ASLayoutableSizeHelperForwarding if ([self _shouldAbortTransitionWithID:transitionID]) { return; } - - // Update display node layout - auto previousLayout = _calculatedDisplayNodeLayout; - auto pendingLayout = std::make_shared( - newLayout, - constrainedSize, - constrainedSize.max - ); - [self setCalculatedDisplayNodeLayout:pendingLayout]; - // Apply complete layout transitions for all subnodes + ASLayout *previousLayout = _calculatedLayout; + [self setCalculatedLayout:newLayout]; + ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) { [node _completePendingLayoutTransition]; node.hierarchyState &= (~ASHierarchyStateLayoutPending); @@ -846,14 +808,13 @@ ASLayoutableSizeHelperForwarding [self _finishOrCancelTransition]; - // Measurement pass completion if (completion) { completion(); } // Setup pending layout transition for animation _pendingLayoutTransition = [[ASLayoutTransition alloc] initWithNode:self - pendingLayout:pendingLayout + pendingLayout:newLayout previousLayout:previousLayout]; // Setup context for pending layout transition. we need to hold a strong reference to the context _pendingLayoutTransitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated @@ -955,8 +916,8 @@ ASLayoutableSizeHelperForwarding } /* - * Hook for subclasses to perform an animation based on the given ASContextTransitioning. By default a fade in and out - * animation is provided. + * Hook for subclasse to perform an animation based on the given ASContextTransitioning. By default a fade in and out + * animation is provided. */ - (void)animateLayoutTransition:(id)context { @@ -969,6 +930,7 @@ ASLayoutableSizeHelperForwarding ASDisplayNode *node = self; NSAssert(node.isNodeLoaded == YES, @"Invalid node state"); + NSAssert([context isAnimated] == YES, @"Can't animate a non-animatable context"); NSArray *removedSubnodes = [context removedSubnodes]; NSMutableArray *removedViews = [NSMutableArray array]; @@ -1069,7 +1031,7 @@ ASLayoutableSizeHelperForwarding { ASDN::MutexLocker l(__instanceLock__); if (_pendingLayoutTransition) { - [self setCalculatedDisplayNodeLayout:_pendingLayoutTransition.pendingLayout]; + [self setCalculatedLayout:_pendingLayoutTransition.pendingLayout]; [self _completeLayoutTransition:_pendingLayoutTransition]; } [self _pendingLayoutTransitionDidComplete]; @@ -1110,8 +1072,7 @@ ASLayoutableSizeHelperForwarding if (_placeholderEnabled && [self _displaysAsynchronously] && self.contents == nil) { // Zero-sized nodes do not require a placeholder. - ASLayout *layout = _calculatedDisplayNodeLayout->layout; - CGSize layoutSize = (layout ? layout.size : CGSizeZero); + CGSize layoutSize = (_calculatedLayout ? _calculatedLayout.size : CGSizeZero); if (CGSizeEqualToSize(layoutSize, CGSizeZero)) { return; } @@ -1302,9 +1263,8 @@ ASLayoutableSizeHelperForwarding __instanceLock__.lock(); - if (_calculatedDisplayNodeLayout->layout == nil) { - // Can't proceed without a layout as no constrained size would be available. If not layout exists at this moment - // no measurement pass did happen just bail out for now + if (_calculatedLayout == nil) { + // Can't proceed without a layout as no constrained size would be available __instanceLock__.unlock(); return; } @@ -1321,11 +1281,11 @@ ASLayoutableSizeHelperForwarding } // This is the root node. Trigger a full measurement pass on *current* thread. Old constrained size is re-used. - [self layoutThatFits:_calculatedDisplayNodeLayout->constrainedSize]; - + [self measureWithSizeRange:_calculatedLayout.constrainedSizeRange]; + CGRect oldBounds = self.bounds; CGSize oldSize = oldBounds.size; - CGSize newSize = _calculatedDisplayNodeLayout->layout.size; + CGSize newSize = _calculatedLayout.size; if (! CGSizeEqualToSize(oldSize, newSize)) { self.bounds = (CGRect){ oldBounds.origin, newSize }; @@ -1386,8 +1346,8 @@ ASLayoutableSizeHelperForwarding CGSize calculatedLayoutSize = CGSizeZero; { ASDN::MutexLocker l(__instanceLock__); - hasDirtyLayout = _calculatedDisplayNodeLayout->isDirty(); - calculatedLayoutSize = _calculatedDisplayNodeLayout->layout.size; + hasDirtyLayout = [self _hasDirtyLayout]; + calculatedLayoutSize = _calculatedLayout.size; } // If no measure pass happened or the bounds changed between layout passes we manually trigger a measurement pass @@ -1396,7 +1356,8 @@ ASLayoutableSizeHelperForwarding if (CGRectEqualToRect(bounds, CGRectZero)) { LOG(@"Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self); } else { - [self layoutThatFits:ASSizeRangeMake(bounds.size)]; + // This is a no op if the bounds size is the same as the cosntrained size we used to create the layout previously + [self measureWithSizeRange:ASSizeRangeMake(bounds.size, bounds.size)]; } } } @@ -2254,14 +2215,6 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) #pragma mark - For Subclasses -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - restrictedToSize:(ASLayoutableSize)size - relativeToParentSize:(CGSize)parentSize -{ - const ASSizeRange resolvedRange = ASSizeRangeIntersect(constrainedSize, ASLayoutableSizeResolve(_size, parentSize)); - return [self calculateLayoutThatFits:resolvedRange]; -} - - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize { __ASDisplayNodeCheckForLayoutMethodOverrides; @@ -2278,14 +2231,14 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASEnvironmentStatePropagateDown(layoutSpec, self.environmentTraitCollection); layoutSpec.isMutable = NO; - ASLayout *layout = [layoutSpec layoutThatFits:constrainedSize]; + ASLayout *layout = [layoutSpec measureWithSizeRange:constrainedSize]; ASDisplayNodeAssertNotNil(layout, @"[ASLayoutSpec measureWithSizeRange:] should never return nil! %@, %@", self, layoutSpec); // Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct. - BOOL isFinalLayoutable = (layout.layoutable != self); + BOOL isFinalLayoutable = (layout.layoutableObject != self); if (isFinalLayoutable) { layout.position = CGPointZero; - layout = [ASLayout layoutWithLayoutable:self size:layout.size sublayouts:@[layout]]; + layout = [ASLayout layoutWithLayoutableObject:self constrainedSizeRange:constrainedSize size:layout.size sublayouts:@[layout]]; #if LAYOUT_VALIDATION ASLayoutableValidateLayout(layout); #endif @@ -2295,7 +2248,9 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) // 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 layoutWithLayoutable:self size:ASSizeRangeClamp(constrainedSize, size) sublayouts:nil]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:ASSizeRangeClamp(constrainedSize, size)]; } } @@ -2304,13 +2259,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) __ASDisplayNodeCheckForLayoutMethodOverrides; ASDN::MutexLocker l(__instanceLock__); - - // Handle deprecated preferred frame size. - if (CGSizeEqualToSize(_preferredFrameSize, CGSizeZero) == NO) { - return _preferredFrameSize; - } - - return CGSizeZero; + return _preferredFrameSize; } - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize @@ -2327,48 +2276,41 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) return [[ASLayoutSpec alloc] init]; } -- (void)setLayoutSpecBlock:(ASLayoutSpecBlock)layoutSpecBlock -{ - // For now there should never be a overwrite of layoutSpecThatFits: and a layoutSpecThatFitsBlock: be provided - ASDisplayNodeAssert(!(_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits), @"Overwriting layoutSpecThatFits: and providing a layoutSpecBlock block is currently not supported"); - - ASDN::MutexLocker l(__instanceLock__); - _layoutSpecBlock = [layoutSpecBlock copy]; -} - -- (ASLayoutSpecBlock)layoutSpecBlock -{ - ASDN::MutexLocker l(__instanceLock__); - return _layoutSpecBlock; -} - - (ASLayout *)calculatedLayout { ASDN::MutexLocker l(__instanceLock__); - return _calculatedDisplayNodeLayout->layout; + return _calculatedLayout; } -- (void)setCalculatedDisplayNodeLayout:(std::shared_ptr)displayNodeLayout +- (void)setCalculatedLayout:(ASLayout *)calculatedLayout { ASDN::MutexLocker l(__instanceLock__); - ASDisplayNodeAssertTrue(displayNodeLayout->layout.layoutable == self); - ASDisplayNodeAssertTrue(displayNodeLayout->layout.size.width >= 0.0); - ASDisplayNodeAssertTrue(displayNodeLayout->layout.size.height >= 0.0); + ASDisplayNodeAssertTrue(calculatedLayout.layoutableObject == self); + ASDisplayNodeAssertTrue(calculatedLayout.size.width >= 0.0); + ASDisplayNodeAssertTrue(calculatedLayout.size.height >= 0.0); - _calculatedDisplayNodeLayout = displayNodeLayout; + _calculatedLayout = calculatedLayout; } - (CGSize)calculatedSize { ASDN::MutexLocker l(__instanceLock__); - return _calculatedDisplayNodeLayout->layout.size; + return _calculatedLayout.size; } - (ASSizeRange)constrainedSizeForCalculatedLayout { ASDN::MutexLocker l(__instanceLock__); - return _calculatedDisplayNodeLayout->constrainedSize; + return _calculatedLayout.constrainedSizeRange; +} + +- (void)setLayoutSpecBlock:(ASLayoutSpecBlock)layoutSpecBlock +{ + // For now there should never be a overwrite of layoutSpecThatFits: and a layoutSpecThatFitsBlock: be provided + ASDisplayNodeAssert(!(_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits), @"Overwriting layoutSpecThatFits: and providing a layoutSpecBlock block is currently not supported"); + + _layoutSpecBlock = layoutSpecBlock; } - (void)setPendingTransitionID:(int32_t)pendingTransitionID @@ -2389,10 +2331,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASDN::MutexLocker l(__instanceLock__); if (! CGSizeEqualToSize(_preferredFrameSize, preferredFrameSize)) { _preferredFrameSize = preferredFrameSize; - - self.width = ASDimensionMake(preferredFrameSize.width); - self.height = ASDimensionMake(preferredFrameSize.height); - + self.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(_preferredFrameSize); [self invalidateCalculatedLayout]; } } @@ -2424,9 +2363,9 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) { ASDN::MutexLocker l(__instanceLock__); - // This will cause the next call to -layoutThatFits:parentSize: to compute a new layout instead of returning - // the cached layout in case the constrained or parent size did not change - _calculatedDisplayNodeLayout->invalidate(); + // This will cause the next call to -measureWithSizeRange: to actually compute a new layout + // instead of returning the current layout + _calculatedLayout.dirty = YES; } - (void)__didLoad @@ -2817,11 +2756,47 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) }); } +- (void)_applyPendingLayoutContext +{ + ASDN::MutexLocker l(__instanceLock__); + if (_pendingLayoutTransition) { + [self _applyLayout:_pendingLayoutTransition.pendingLayout layoutTransition:_pendingLayoutTransition]; + _pendingLayoutTransition = nil; + } +} + +- (void)_applyLayout:(ASLayout *)layout layoutTransition:(ASLayoutTransition *)layoutTransition +{ + ASDN::MutexLocker l(__instanceLock__); + _calculatedLayout = layout; + + ASDisplayNodeAssertTrue(layout.layoutableObject == self); + ASDisplayNodeAssertTrue(layout.size.width >= 0.0); + ASDisplayNodeAssertTrue(layout.size.height >= 0.0); + + if (layoutTransition == nil || self.automaticallyManagesSubnodes == NO) { + return; + } + + // Trampoline to the main thread if necessary + if (ASDisplayNodeThreadIsMain() == NO && layoutTransition.isSynchronous == NO) { + + // Subnode insertions and removals need to happen always on the main thread if at least one subnode is already loaded + ASPerformBlockOnMainThread(^{ + [layoutTransition commitTransition]; + }); + + return; + } + + [layoutTransition commitTransition]; +} + - (void)layout { ASDisplayNodeAssertMainThread(); - if (_calculatedDisplayNodeLayout->isDirty()) { + if ([self _hasDirtyLayout]) { return; } @@ -2830,8 +2805,8 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) - (void)__layoutSublayouts { - for (ASLayout *subnodeLayout in _calculatedDisplayNodeLayout->layout.sublayouts) { - ((ASDisplayNode *)subnodeLayout.layoutable).frame = subnodeLayout.frame; + for (ASLayout *subnodeLayout in _calculatedLayout.sublayouts) { + ((ASDisplayNode *)subnodeLayout.layoutableObject).frame = [subnodeLayout frame]; } } @@ -3230,19 +3205,6 @@ ASEnvironmentLayoutExtensibilityForwarding } } #endif - -#pragma mark - Deprecated - -- (CGSize)measure:(CGSize)constrainedSize -{ - return [self layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; -} - -- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize -{ - return [self layoutThatFits:constrainedSize parentSize:constrainedSize.max]; -} - @end @implementation ASDisplayNode (Debugging) diff --git a/AsyncDisplayKit/ASImageNode.mm b/AsyncDisplayKit/ASImageNode.mm index da6ce21b..706c09c4 100644 --- a/AsyncDisplayKit/ASImageNode.mm +++ b/AsyncDisplayKit/ASImageNode.mm @@ -14,12 +14,10 @@ #import "_ASDisplayLayer.h" #import "ASAssert.h" -#import "ASDimension.h" #import "ASDisplayNode+Subclasses.h" #import "ASDisplayNodeInternal.h" #import "ASDisplayNodeExtras.h" #import "ASDisplayNode+Beta.h" -#import "ASLayout.h" #import "ASTextNode.h" #import "ASImageNode+AnimatedImagePrivate.h" @@ -188,23 +186,13 @@ struct ASImageNodeDrawParameters { - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { ASDN::MutexLocker l(__instanceLock__); - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - // If a preferredFrameSize is set, call the superclass to return that instead of using the image size. - if (CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero) == NO) { -#if DEBUG - NSLog(@"Using -[ASDisplayNode preferredFrameSize] is deprecated."); -#endif - return self.preferredFrameSize; - } -#pragma clang diagnostic pop - - if (_image == nil) { - return constrainedSize; - } - - return _image.size; + // if a preferredFrameSize is set, call the superclass to return that instead of using the image size. + if (CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero) == NO) + return [super calculateSizeThatFits:constrainedSize]; + else if (_image) + return _image.size; + else + return CGSizeZero; } #pragma mark - Setter / Getter @@ -657,7 +645,7 @@ static ASDN::Mutex cacheLock; if (_debugLabelNode) { CGSize boundsSize = self.bounds.size; - CGSize debugLabelSize = [_debugLabelNode layoutThatFits:ASSizeRangeMake(CGSizeZero, boundsSize)].size; + CGSize debugLabelSize = [_debugLabelNode measure:boundsSize]; CGPoint debugLabelOrigin = CGPointMake(boundsSize.width - debugLabelSize.width, boundsSize.height - debugLabelSize.height); _debugLabelNode.frame = (CGRect) {debugLabelOrigin, debugLabelSize}; diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index d1882231..1e3ec857 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -392,14 +392,21 @@ - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { - // FIXME: Need a better way to allow maps to take up the right amount of space in a layout (sizeRange, etc) - // These fallbacks protect against inheriting a constrainedSize that contains a CGFLOAT_MAX value. - if (!ASIsCGSizeValidForLayout(constrainedSize)) { - //ASDisplayNodeAssert(NO, @"Invalid width or height in ASMapNode"); - constrainedSize = CGSizeZero; + CGSize size = self.preferredFrameSize; + if (CGSizeEqualToSize(size, CGSizeZero)) { + size = constrainedSize; + + // FIXME: Need a better way to allow maps to take up the right amount of space in a layout (sizeRange, etc) + // These fallbacks protect against inheriting a constrainedSize that contains a CGFLOAT_MAX value. + if (!isValidForLayout(size.width)) { + size.width = 100.0; + } + if (!isValidForLayout(size.height)) { + size.height = 100.0; + } } - [self setSnapshotSizeWithReloadIfNeeded:constrainedSize]; - return constrainedSize; + [self setSnapshotSizeWithReloadIfNeeded:size]; + return size; } - (void)calculatedLayoutDidChange diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 842a6842..8dc50524 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -1130,7 +1130,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; CGSizeMake(_nodesConstrainedWidth, delegateConstrainedSize.max.height)); } else { constrainedSize = ASSizeRangeMake(CGSizeMake(_nodesConstrainedWidth, 0), - CGSizeMake(_nodesConstrainedWidth, CGFLOAT_MAX)); + CGSizeMake(_nodesConstrainedWidth, FLT_MAX)); } return constrainedSize; } @@ -1186,7 +1186,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; // Also, in many cases, some nodes may not need to be re-measured at all, such as when user enters and then immediately leaves editing mode. // To avoid premature optimization and making such assumption, as well as to keep ASTableView simple, re-measurement is strictly done on main. [self beginUpdates]; - const CGSize calculatedSize = [node layoutThatFits:constrainedSize].size; + CGSize calculatedSize = [[node measureWithSizeRange:constrainedSize] size]; node.frame = CGRectMake(0, 0, calculatedSize.width, calculatedSize.height); [self endUpdates]; } diff --git a/AsyncDisplayKit/ASVideoNode.mm b/AsyncDisplayKit/ASVideoNode.mm index 5395b3ed..8ba56f1d 100644 --- a/AsyncDisplayKit/ASVideoNode.mm +++ b/AsyncDisplayKit/ASVideoNode.mm @@ -240,17 +240,10 @@ static NSString * const kRate = @"rate"; ASDN::MutexLocker l(__instanceLock__); CGSize calculatedSize = constrainedSize; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" // if a preferredFrameSize is set, call the superclass to return that instead of using the image size. - if (CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero) == NO) { -#if DEBUG - NSLog(@"Using -[ASDisplayNde preferredFrameSize] is deprecated."); -#endif + if (CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero) == NO) calculatedSize = self.preferredFrameSize; - } -#pragma clang diagnostic pop - + // Prevent crashes through if infinite width or height if (isinf(calculatedSize.width) || isinf(calculatedSize.height)) { ASDisplayNodeAssert(NO, @"Infinite width or height in ASVideoNode"); @@ -258,9 +251,8 @@ static NSString * const kRate = @"rate"; } if (_playerNode) { - _playerNode.width = ASDimensionMake(calculatedSize.width); - _playerNode.height = ASDimensionMake(calculatedSize.height); - [_playerNode layoutThatFits:ASSizeRangeMake(CGSizeZero, calculatedSize)]; + _playerNode.preferredFrameSize = calculatedSize; + [_playerNode measure:calculatedSize]; } return calculatedSize; diff --git a/AsyncDisplayKit/ASVideoPlayerNode.mm b/AsyncDisplayKit/ASVideoPlayerNode.mm index 46779888..f105aa4b 100644 --- a/AsyncDisplayKit/ASVideoPlayerNode.mm +++ b/AsyncDisplayKit/ASVideoPlayerNode.mm @@ -324,9 +324,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext; { if (_playbackButtonNode == nil) { _playbackButtonNode = [[ASDefaultPlaybackButton alloc] init]; - _playbackButtonNode.width = ASDimensionMakeWithPoints(16.0); - _playbackButtonNode.height = ASDimensionMakeWithPoints(22.0); - + _playbackButtonNode.preferredFrameSize = CGSizeMake(16.0, 22.0); if (_delegateFlags.delegatePlaybackButtonTint) { _playbackButtonNode.tintColor = [_delegate videoPlayerNodePlaybackButtonTint:self]; } else { @@ -600,9 +598,7 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext; return spinnnerView; }]; - - _spinnerNode.width = ASDimensionMakeWithPoints(44.0); - _spinnerNode.height = ASDimensionMakeWithPoints(44.0); + _spinnerNode.preferredFrameSize = CGSizeMake(44.0, 44.0); [self addSubnode:_spinnerNode]; [self setNeedsLayout]; @@ -693,21 +689,23 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext; return controls; } - #pragma mark - Layout - -- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +- (ASLayoutSpec*)layoutSpecThatFits:(ASSizeRange)constrainedSize { CGSize maxSize = constrainedSize.max; + if (!CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero)) { + maxSize = self.preferredFrameSize; + } // Prevent crashes through if infinite width or height if (isinf(maxSize.width) || isinf(maxSize.height)) { ASDisplayNodeAssert(NO, @"Infinite width or height in ASVideoPlayerNode"); maxSize = CGSizeZero; } - _videoNode.size = ASLayoutableSizeMakeFromCGSize(maxSize); + _videoNode.preferredFrameSize = maxSize; ASLayoutSpec *layoutSpec; + if (_delegateFlags.delegateLayoutSpecForControls) { layoutSpec = [_delegate videoPlayerNodeLayoutSpec:self forControls:_cachedControls forMaximumSize:maxSize]; } else { @@ -718,21 +716,21 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext; if (_spinnerNode) { ASCenterLayoutSpec *centerLayoutSpec = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:_spinnerNode]; - centerLayoutSpec.size = ASLayoutableSizeMakeFromCGSize(maxSize); + centerLayoutSpec.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(maxSize); [children addObject:centerLayoutSpec]; } ASOverlayLayoutSpec *overlaySpec = [ASOverlayLayoutSpec overlayLayoutSpecWithChild:_videoNode overlay:layoutSpec]; - overlaySpec.size = ASLayoutableSizeMakeFromCGSize(maxSize); + overlaySpec.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(maxSize); + [children addObject:overlaySpec]; return [ASStaticLayoutSpec staticLayoutSpecWithChildren:children]; } -- (ASLayoutSpec *)defaultLayoutSpecThatFits:(CGSize)maxSize +- (ASLayoutSpec*)defaultLayoutSpecThatFits:(CGSize)maxSize { - _scrubberNode.width = ASDimensionMakeWithPoints(maxSize.width); - _scrubberNode.height = ASDimensionMakeWithPoints(44.0); + _scrubberNode.preferredFrameSize = CGSizeMake(maxSize.width, 44.0); ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init]; spacer.flexGrow = YES; diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index 4b309067..fd9b67c9 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -15,7 +15,6 @@ #import "ASAvailability.h" #import "ASDisplayNodeInternal.h" #import "ASDisplayNode+FrameworkPrivate.h" -#import "ASLayout.h" #import "ASTraitCollection.h" #import "ASEnvironmentInternal.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" @@ -106,7 +105,7 @@ [self progagateNewEnvironmentTraitCollection:environmentTraitCollection]; }]; } else { - [_node layoutThatFits:[self nodeConstrainedSize]]; + [_node measureWithSizeRange:[self nodeConstrainedSize]]; } if (!AS_AT_LEAST_IOS9) { @@ -133,7 +132,7 @@ ASVisibilityDidMoveToParentViewController; // We do this early layout because we need to get any ASCollectionNodes etc. into the // hierarchy before UIKit applies the scroll view inset adjustments, if you are using // automatic subnode management. - [_node layoutThatFits:[self nodeConstrainedSize]]; + [_node measureWithSizeRange:[self nodeConstrainedSize]]; [_node recursivelyFetchData]; @@ -303,7 +302,7 @@ ASVisibilityDepthImplementation; // once we've propagated all the traits, layout this node. // Remeasure the node with the latest constrained size – old constrained size may be incorrect. - [self.node layoutThatFits:[self nodeConstrainedSize]]; + [self.node measureWithSizeRange:[self nodeConstrainedSize]]; [self.node setNeedsLayout]; } } diff --git a/AsyncDisplayKit/AsyncDisplayKit+Debug.m b/AsyncDisplayKit/AsyncDisplayKit+Debug.m index ae32b38d..844f52e4 100644 --- a/AsyncDisplayKit/AsyncDisplayKit+Debug.m +++ b/AsyncDisplayKit/AsyncDisplayKit+Debug.m @@ -15,7 +15,6 @@ #import "ASDisplayNodeExtras.h" #import "ASWeakSet.h" #import "UIImage+ASConvenience.h" -#import #import #import #import @@ -613,7 +612,7 @@ static BOOL __shouldShowRangeDebugOverlay = NO; [self setBarSubviewOrder]; CGRect rect = CGRectIntegral(CGRectMake(0, 0, boundsSize.width, floorf(boundsSize.height / 2.0))); - rect.size = [_debugText layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX))].size; + rect.size = [_debugText measure:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; rect.origin.x = (boundsSize.width - rect.size.width) / 2.0; _debugText.frame = rect; rect.origin.y += rect.size.height; diff --git a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m index 4fa8abdb..d548d937 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m +++ b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m @@ -22,9 +22,9 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView *collectionView) { CGSize maxSize = collectionView.bounds.size; if (ASScrollDirectionContainsHorizontalDirection(collectionView.scrollableDirections)) { - maxSize.width = CGFLOAT_MAX; + maxSize.width = FLT_MAX; } else { - maxSize.height = CGFLOAT_MAX; + maxSize.height = FLT_MAX; } return ASSizeRangeMake(CGSizeZero, maxSize); } diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index b0f7ece2..e6ec2b76 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -155,7 +155,7 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind"; - (void)_layoutNode:(ASCellNode *)node withConstrainedSize:(ASSizeRange)constrainedSize { CGRect frame = CGRectZero; - frame.size = [node layoutThatFits:constrainedSize].size; + frame.size = [node measureWithSizeRange:constrainedSize].size; node.frame = frame; } diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 120ef69f..4dad9fde 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -12,6 +12,7 @@ #import #import +#import @protocol ASEnvironment; @class UITraitCollection; @@ -39,11 +40,12 @@ typedef struct ASEnvironmentLayoutOptionsState { CGFloat spacingAfter;// = 0; BOOL flexGrow;// = NO; BOOL flexShrink;// = NO; - ASDimension flexBasis;// = ASRelativeDimensionAuto; + ASRelativeDimension flexBasis;// = ASRelativeDimensionUnconstrained; ASStackLayoutAlignSelf alignSelf;// = ASStackLayoutAlignSelfAuto; CGFloat ascender;// = 0; CGFloat descender;// = 0; + ASRelativeSizeRange sizeRange;// = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero));; CGPoint layoutPosition;// = CGPointZero; struct ASEnvironmentStateExtensions _extensions; diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h index 0527f982..0d2d5837 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h @@ -8,6 +8,7 @@ // of patent rights can be found in the PATENTS file in the same directory. // +#import #import diff --git a/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm b/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm index f90acb36..99ec4061 100644 --- a/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm @@ -39,26 +39,26 @@ static NSUInteger const kBackgroundChildIndex = 1; } /** - * First layout the contents, then fit the background image. + First layout the contents, then fit the background image. */ -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - restrictedToSize:(ASLayoutableSize)size - relativeToParentSize:(CGSize)parentSize +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { - ASLayout *contentsLayout = [self.child layoutThatFits:constrainedSize parentSize:parentSize]; + ASLayout *contentsLayout = [[self child] measureWithSizeRange:constrainedSize]; NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:2]; if (self.background) { // Size background to exactly the same size. - ASLayout *backgroundLayout = [self.background layoutThatFits:ASSizeRangeMake(contentsLayout.size) - parentSize:parentSize]; + ASLayout *backgroundLayout = [self.background measureWithSizeRange:{contentsLayout.size, contentsLayout.size}]; backgroundLayout.position = CGPointZero; [sublayouts addObject:backgroundLayout]; } contentsLayout.position = CGPointZero; [sublayouts addObject:contentsLayout]; - return [ASLayout layoutWithLayoutable:self size:contentsLayout.size sublayouts:sublayouts]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:contentsLayout.size + sublayouts:sublayouts]; } - (void)setBackground:(id)background diff --git a/AsyncDisplayKit/Layout/ASDimension.h b/AsyncDisplayKit/Layout/ASDimension.h index d1710ca2..79e7e2f6 100644 --- a/AsyncDisplayKit/Layout/ASDimension.h +++ b/AsyncDisplayKit/Layout/ASDimension.h @@ -11,203 +11,58 @@ #pragma once #import #import -#import -ASDISPLAYNODE_INLINE BOOL ASPointsAreValidForLayout(CGFloat points) -{ - return ((isnormal(points) || points == 0.0) && points >= 0.0 && points < (CGFLOAT_MAX / 2.0)); -} - -ASDISPLAYNODE_INLINE BOOL ASIsCGSizeValidForLayout(CGSize size) -{ - return (ASPointsAreValidForLayout(size.width) && ASPointsAreValidForLayout(size.height)); -} - -/** - * A dimension relative to constraints to be provided in the future. - * A ASDimension can be one of three types: - * - * "Auto" - This indicated "I have no opinion" and may be resolved in whatever way makes most sense given the circumstances. - * - * "Points" - Just a number. It will always resolve to exactly this amount. - * - * "Percent" - Multiplied to a provided parent amount to resolve a final amount. - */ -typedef NS_ENUM(NSInteger, ASDimensionUnit) { - /** This indicates "I have no opinion" and may be resolved in whatever way makes most sense given the circumstances. */ - ASDimensionUnitAuto, +/** A dimension relative to constraints to be provided in the future. */ +typedef NS_ENUM(NSInteger, ASRelativeDimensionType) { /** Just a number. It will always resolve to exactly this amount. This is the default type. */ - ASDimensionUnitPoints, + ASRelativeDimensionTypePoints, /** Multiplied to a provided parent amount to resolve a final amount. */ - ASDimensionUnitFraction, + ASRelativeDimensionTypeFraction, }; typedef struct { - ASDimensionUnit unit; + ASRelativeDimensionType type; CGFloat value; -} ASDimension; +} ASRelativeDimension; -/** - * Expresses an inclusive range of sizes. Used to provide a simple constraint to layout. - */ +/** Expresses an inclusive range of sizes. Used to provide a simple constraint to layout. */ typedef struct { CGSize min; CGSize max; } ASSizeRange; -/** - * A struct specifying a ASLayoutable's size. Example: - * - * ASLayoutableSize size = (ASLayoutableSize){ - * .width = ASDimensionMakeWithFraction(0.25), - * .maxWidth = ASDimensionMakeWithPoints(200), - * .minHeight = ASDimensionMakeWithFraction(0.50) - * }; - * - * Description: - * - */ -typedef struct { - ASDimension width; - ASDimension height; - ASDimension minWidth; - ASDimension maxWidth; - ASDimension minHeight; - ASDimension maxHeight; -} ASLayoutableSize; +extern ASRelativeDimension const ASRelativeDimensionUnconstrained; -extern ASDimension const ASDimensionAuto; +#define isValidForLayout(x) ((isnormal(x) || x == 0.0) && x >= 0.0 && x < (CGFLOAT_MAX / 2.0)) ASDISPLAYNODE_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN +#pragma mark - ASRelativeDimension -#pragma mark - ASDimension +extern ASRelativeDimension ASRelativeDimensionMake(ASRelativeDimensionType type, CGFloat value); -/** - * Returns a dimension with the specified type and value. - */ -ASOVERLOADABLE ASDISPLAYNODE_INLINE ASDimension ASDimensionMake(ASDimensionUnit unit, CGFloat value) -{ - if (unit == ASDimensionUnitPoints) { - ASDisplayNodeCAssertPositiveReal(@"Points", value); - } else if (unit == ASDimensionUnitFraction) { - // TODO: Enable this assertion for 2.0. Check that there is no use case for using a larger value, e.g. to layout for a clipsToBounds = NO element. - // ASDisplayNodeCAssert( 0 <= value && value <= 1.0, @"ASDimension fraction value (%f) must be between 0 and 1.", value); - } - ASDimension dimension; - dimension.unit = unit; - dimension.value = value; - return dimension; -} +extern ASRelativeDimension ASRelativeDimensionMakeWithPoints(CGFloat points); -/** - * Returns a dimension with the specified points value. - */ -ASOVERLOADABLE ASDISPLAYNODE_INLINE ASDimension ASDimensionMake(CGFloat points) -{ - return ASDimensionMake(ASDimensionUnitPoints, points); -} +extern ASRelativeDimension ASRelativeDimensionMakeWithFraction(CGFloat fraction); -/** - * Returns a dimension by parsing the specified dimension string. - * Examples: ASDimensionMake(@"0.5%") = ASDimensionMake(ASDimensionUnitFraction, 0.5) - * ASDimensionMake(@"0.5pt") = ASDimensionMake(ASDimensionUnitPoints, 0.5) - */ -ASOVERLOADABLE extern ASDimension ASDimensionMake(NSString *dimension); +extern ASRelativeDimension ASRelativeDimensionCopy(ASRelativeDimension aDimension); -/** - * Returns a dimension with the specified points value. - */ -ASDISPLAYNODE_INLINE ASDimension ASDimensionMakeWithPoints(CGFloat points) -{ - ASDisplayNodeCAssertPositiveReal(@"Points", points); - return ASDimensionMake(ASDimensionUnitPoints, points); -} +extern BOOL ASRelativeDimensionEqualToRelativeDimension(ASRelativeDimension lhs, ASRelativeDimension rhs); -/** - * Returns a dimension with the specified fraction value. - */ -ASDISPLAYNODE_INLINE ASDimension ASDimensionMakeWithFraction(CGFloat fraction) -{ - ASDisplayNodeCAssert( 0 <= fraction && fraction <= 1.0, @"ASDimension fraction value (%f) must be between 0 and 1.", fraction); - return ASDimensionMake(ASDimensionUnitFraction, fraction); -} - -/** - * Returns whether two dimensions are equal. - */ -ASDISPLAYNODE_INLINE BOOL ASDimensionEqualToDimension(ASDimension lhs, ASDimension rhs) -{ - return (lhs.unit == rhs.unit && lhs.value == rhs.value); -} - -/** - * Returns a NSString representation of a dimension. - */ -extern NSString *NSStringFromASDimension(ASDimension dimension); - -/** - * Resolve this dimension to a parent size. - */ -ASDISPLAYNODE_INLINE CGFloat ASDimensionResolve(ASDimension dimension, CGFloat parentSize, CGFloat autoSize) -{ - switch (dimension.unit) { - case ASDimensionUnitAuto: - return autoSize; - case ASDimensionUnitPoints: - return dimension.value; - case ASDimensionUnitFraction: - return dimension.value * parentSize; - } -} - - -#pragma mark - NSNumber+ASDimension - -@interface NSNumber (ASDimension) -@property (nonatomic, readonly) ASDimension as_pointDimension; -@property (nonatomic, readonly) ASDimension as_fractionDimension; -@end +extern NSString *NSStringFromASRelativeDimension(ASRelativeDimension dimension); +extern CGFloat ASRelativeDimensionResolve(ASRelativeDimension dimension, CGFloat parent); #pragma mark - ASSizeRange -/** - * Creates an ASSizeRange with provided min and max size. - */ -ASOVERLOADABLE ASDISPLAYNODE_INLINE ASSizeRange ASSizeRangeMake(CGSize min, CGSize max) -{ - ASDisplayNodeCAssertPositiveReal(@"Range min width", min.width); - ASDisplayNodeCAssertPositiveReal(@"Range min height", min.height); - ASDisplayNodeCAssertInfOrPositiveReal(@"Range max width", max.width); - ASDisplayNodeCAssertInfOrPositiveReal(@"Range max height", max.height); - ASDisplayNodeCAssert(min.width <= max.width, - @"Range min width (%f) must not be larger than max width (%f).", min.width, max.width); - ASDisplayNodeCAssert(min.height <= max.height, - @"Range min height (%f) must not be larger than max height (%f).", min.height, max.height); - ASSizeRange sizeRange; - sizeRange.min = min; - sizeRange.max = max; - return sizeRange; -} +extern ASSizeRange ASSizeRangeMake(CGSize min, CGSize max); -/** - * Creates an ASSizeRange with provided size as both min and max. - */ -ASOVERLOADABLE ASDISPLAYNODE_INLINE ASSizeRange ASSizeRangeMake(CGSize exactSize) -{ - return ASSizeRangeMake(exactSize, exactSize); -} +/** Creates an ASSizeRange with the provided size as both min and max */ +extern ASSizeRange ASSizeRangeMakeExactSize(CGSize size); -/** - * Clamps the provided CGSize between the [min, max] bounds of this ASSizeRange. - */ -ASDISPLAYNODE_INLINE CGSize ASSizeRangeClamp(ASSizeRange sizeRange, CGSize size) -{ - return CGSizeMake(MAX(sizeRange.min.width, MIN(sizeRange.max.width, size.width)), - MAX(sizeRange.min.height, MIN(sizeRange.max.height, size.height))); -} +/** Clamps the provided CGSize between the [min, max] bounds of this ASSizeRange. */ +extern CGSize ASSizeRangeClamp(ASSizeRange sizeRange, CGSize size); /** * Intersects another size range. If the other size range does not overlap in either dimension, this size range @@ -215,91 +70,9 @@ ASDISPLAYNODE_INLINE CGSize ASSizeRangeClamp(ASSizeRange sizeRange, CGSize size) */ extern ASSizeRange ASSizeRangeIntersect(ASSizeRange sizeRange, ASSizeRange otherSizeRange); -/** - * Returns whether two size ranges are equal in min and max size - */ -ASDISPLAYNODE_INLINE BOOL ASSizeRangeEqualToSizeRange(ASSizeRange lhs, ASSizeRange rhs) -{ - return CGSizeEqualToSize(lhs.min, rhs.min) && CGSizeEqualToSize(lhs.max, rhs.max); -} +extern BOOL ASSizeRangeEqualToSizeRange(ASSizeRange lhs, ASSizeRange rhs); -/** - * Returns a string representation of a size range - */ extern NSString *NSStringFromASSizeRange(ASSizeRange sizeRange); - -#pragma mark - ASLayoutableSize - -/** - * Returns an ASLayoutableSize with default values. - */ -ASDISPLAYNODE_INLINE ASLayoutableSize ASLayoutableSizeMake() -{ - return (ASLayoutableSize){ - .width = ASDimensionAuto, - .height = ASDimensionAuto, - .minWidth = ASDimensionAuto, - .maxWidth = ASDimensionAuto, - .minHeight = ASDimensionAuto, - .maxHeight = ASDimensionAuto - }; -} - -/** - * Returns an ASLayoutableSize with the specified CGSize values as width and height. - */ -ASDISPLAYNODE_INLINE ASLayoutableSize ASLayoutableSizeMakeFromCGSize(CGSize size) -{ - ASLayoutableSize s = ASLayoutableSizeMake(); - s.width = ASDimensionMakeWithPoints(size.width); - s.height = ASDimensionMakeWithPoints(size.height); - return s; -} - -/** - * Returns whether two sizes are equal. - */ -ASDISPLAYNODE_INLINE BOOL ASLayoutableSizeEqualToLayoutableSize(ASLayoutableSize lhs, ASLayoutableSize rhs) -{ - return (ASDimensionEqualToDimension(lhs.width, rhs.width) - && ASDimensionEqualToDimension(lhs.height, rhs.height) - && ASDimensionEqualToDimension(lhs.minWidth, rhs.minWidth) - && ASDimensionEqualToDimension(lhs.maxWidth, rhs.maxWidth) - && ASDimensionEqualToDimension(lhs.minHeight, rhs.minHeight) - && ASDimensionEqualToDimension(lhs.maxHeight, rhs.maxHeight)); -} - -/** - * Returns a string formatted to contain the data from an ASLayoutableSize. - */ -extern NSString *NSStringFromASLayoutableSize(ASLayoutableSize size); - -/** - * Resolve the given size relative to a parent size and an auto size. - * From the given size uses width, height to resolve the exact size constraint, uses the minHeight and minWidth to - * resolve the min size constraint and the maxHeight and maxWidth to resolve the max size constraint. For every - * dimension with unit ASDimensionUnitAuto the given autoASSizeRange value will be used. - * Based on the calculated exact, min and max size constraints the final size range will be calculated. - */ -extern ASSizeRange ASLayoutableSizeResolveAutoSize(ASLayoutableSize size, const CGSize parentSize, ASSizeRange autoASSizeRange); - -/** - * Resolve the given size to a parent size. Uses internally ASLayoutableSizeResolveAutoSize with {INFINITY, INFINITY} as - * as autoASSizeRange. For more information look at ASLayoutableSizeResolveAutoSize. - */ -ASDISPLAYNODE_INLINE ASSizeRange ASLayoutableSizeResolve(ASLayoutableSize size, const CGSize parentSize) -{ - return ASLayoutableSizeResolveAutoSize(size, parentSize, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY))); -} - - -#pragma mark - Deprecated - -/** - * Function is deprecated. Use ASSizeRangeMakeWithExactCGSize instead. - */ -extern ASSizeRange ASSizeRangeMakeExactSize(CGSize size) ASDISPLAYNODE_DEPRECATED; - NS_ASSUME_NONNULL_END ASDISPLAYNODE_EXTERN_C_END diff --git a/AsyncDisplayKit/Layout/ASDimension.mm b/AsyncDisplayKit/Layout/ASDimension.mm index 6f5f232d..a60b6b4b 100644 --- a/AsyncDisplayKit/Layout/ASDimension.mm +++ b/AsyncDisplayKit/Layout/ASDimension.mm @@ -11,164 +11,89 @@ #import "ASDimension.h" #import "ASAssert.h" -#pragma mark - ASDimension +ASRelativeDimension const ASRelativeDimensionUnconstrained = {}; -ASDimension const ASDimensionAuto = {ASDimensionUnitAuto, 0}; +#pragma mark - ASRelativeDimension -ASOVERLOADABLE ASDimension ASDimensionMake(NSString *dimension) +ASRelativeDimension ASRelativeDimensionMake(ASRelativeDimensionType type, CGFloat value) { - // Handle empty string - if (dimension.length == 0) { - return ASDimensionMake(ASDimensionUnitPoints, 0.0); + if (type == ASRelativeDimensionTypePoints) { + ASDisplayNodeCAssertPositiveReal(@"Points", value); + } else if (type == ASRelativeDimensionTypeFraction) { + // TODO: Enable this assertion for 2.0. Check that there is no use case for using a larger value, e.g. to layout for a clipsToBounds = NO element. + // ASDisplayNodeCAssert( 0 <= value && value <= 1.0, @"ASRelativeDimension fraction value (%f) must be between 0 and 1.", value); } - - // Handle points - NSUInteger pointsStringLocation = [dimension rangeOfString:@"pt"].location; - if (pointsStringLocation != NSNotFound) { - // Check if points is at the end and remove it - if (pointsStringLocation == (dimension.length-2)) { - dimension = [dimension substringToIndex:(dimension.length-2)]; - return ASDimensionMake(ASDimensionUnitPoints, dimension.floatValue); - } - } - - // Handle fraction - NSUInteger percentStringLocation = [dimension rangeOfString:@"%"].location; - if (percentStringLocation != NSNotFound) { - // Check if percent is at the end and remove it - if (percentStringLocation == (dimension.length-1)) { - dimension = [dimension substringToIndex:(dimension.length-1)]; - return ASDimensionMake(ASDimensionUnitFraction, dimension.floatValue); - } - } - - // Assert as parsing went wrong - ASDisplayNodeCAssert(NO, @"Parsing dimension failed for: %@", dimension); - return ASDimensionAuto; + ASRelativeDimension dimension; dimension.type = type; dimension.value = value; return dimension; } -NSString *NSStringFromASDimension(ASDimension dimension) +ASRelativeDimension ASRelativeDimensionMakeWithPoints(CGFloat points) { - switch (dimension.unit) { - case ASDimensionUnitPoints: + ASDisplayNodeCAssertPositiveReal(@"Points", points); + return ASRelativeDimensionMake(ASRelativeDimensionTypePoints, points); +} + +ASRelativeDimension ASRelativeDimensionMakeWithFraction(CGFloat fraction) +{ + // ASDisplayNodeCAssert( 0 <= fraction && fraction <= 1.0, @"ASRelativeDimension fraction value (%f) must be between 0 and 1.", fraction); + return ASRelativeDimensionMake(ASRelativeDimensionTypeFraction, fraction); +} + +ASRelativeDimension ASRelativeDimensionCopy(ASRelativeDimension aDimension) +{ + return ASRelativeDimensionMake(aDimension.type, aDimension.value); +} + +BOOL ASRelativeDimensionEqualToRelativeDimension(ASRelativeDimension lhs, ASRelativeDimension rhs) +{ + return lhs.type == rhs.type && lhs.value == rhs.value; +} + +NSString *NSStringFromASRelativeDimension(ASRelativeDimension dimension) +{ + switch (dimension.type) { + case ASRelativeDimensionTypePoints: return [NSString stringWithFormat:@"%.0fpt", dimension.value]; - case ASDimensionUnitFraction: + case ASRelativeDimensionTypeFraction: return [NSString stringWithFormat:@"%.0f%%", dimension.value * 100.0]; - case ASDimensionUnitAuto: - return @"Auto"; } } - -#pragma mark - NSNumber+ASDimension - -@implementation NSNumber (ASDimension) - -- (ASDimension)as_pointDimension +CGFloat ASRelativeDimensionResolve(ASRelativeDimension dimension, CGFloat parent) { - return ASDimensionMake(ASDimensionUnitPoints, self.floatValue); + switch (dimension.type) { + case ASRelativeDimensionTypePoints: + return dimension.value; + case ASRelativeDimensionTypeFraction: + return dimension.value * parent; + } } -- (ASDimension)as_fractionDimension -{ - return ASDimensionMake(ASDimensionUnitFraction, self.floatValue); -} - -@end - - -#pragma mark - ASRelativeSize - -/** - * Expresses a size with relative dimensions. Only used for calculations internally in ASDimension.h - */ -typedef struct { - ASDimension width; - ASDimension height; -} ASRelativeSize; - -ASDISPLAYNODE_INLINE ASRelativeSize ASRelativeSizeMake(ASDimension width, ASDimension height) -{ - ASRelativeSize size; - size.width = width; - size.height = height; - return size; -} - -// ** Resolve this relative size relative to a parent size. */ -ASDISPLAYNODE_INLINE CGSize ASRelativeSizeResolveSize(ASRelativeSize relativeSize, CGSize parentSize, CGSize autoSize) -{ - return CGSizeMake(ASDimensionResolve(relativeSize.width, parentSize.width, autoSize.width), - ASDimensionResolve(relativeSize.height, parentSize.height, autoSize.height)); -} - -// ** Returns a string formatted to contain the data from an ASRelativeSize. */ -ASDISPLAYNODE_INLINE NSString *NSStringFromASRelativeSize(ASRelativeSize size) -{ - return [NSString stringWithFormat:@"{%@, %@}", - NSStringFromASDimension(size.width), - NSStringFromASDimension(size.height)]; -} - - -#pragma mark - ASLayoutableSize - -NSString *NSStringFromASLayoutableSize(ASLayoutableSize size) -{ - return [NSString stringWithFormat: - @"", - NSStringFromASRelativeSize(ASRelativeSizeMake(size.width, size.height)), - NSStringFromASRelativeSize(ASRelativeSizeMake(size.minWidth, size.minHeight)), - NSStringFromASRelativeSize(ASRelativeSizeMake(size.maxWidth, size.maxHeight))]; -} - -ASDISPLAYNODE_INLINE void ASLayoutableSizeConstrain(CGFloat minVal, CGFloat exactVal, CGFloat maxVal, CGFloat *outMin, CGFloat *outMax) -{ - NSCAssert(!isnan(minVal), @"minVal must not be NaN"); - NSCAssert(!isnan(maxVal), @"maxVal must not be NaN"); - // Avoid use of min/max primitives since they're harder to reason - // about in the presence of NaN (in exactVal) - // Follow CSS: min overrides max overrides exact. - - // Begin with the min/max range - *outMin = minVal; - *outMax = maxVal; - if (maxVal <= minVal) { - // min overrides max and exactVal is irrelevant - *outMax = minVal; - return; - } - if (isnan(exactVal)) { - // no exact value, so leave as a min/max range - return; - } - if (exactVal > maxVal) { - // clip to max value - *outMin = maxVal; - } else if (exactVal < minVal) { - // clip to min value - *outMax = minVal; - } else { - // use exact value - *outMin = *outMax = exactVal; - } -} - -ASSizeRange ASLayoutableSizeResolveAutoSize(ASLayoutableSize size, const CGSize parentSize, ASSizeRange autoASSizeRange) -{ - CGSize resolvedExact = ASRelativeSizeResolveSize(ASRelativeSizeMake(size.width, size.height), parentSize, {NAN, NAN}); - CGSize resolvedMin = ASRelativeSizeResolveSize(ASRelativeSizeMake(size.minWidth, size.minHeight), parentSize, autoASSizeRange.min); - CGSize resolvedMax = ASRelativeSizeResolveSize(ASRelativeSizeMake(size.maxWidth, size.maxHeight), parentSize, autoASSizeRange.max); - - CGSize rangeMin, rangeMax; - ASLayoutableSizeConstrain(resolvedMin.width, resolvedExact.width, resolvedMax.width, &rangeMin.width, &rangeMax.width); - ASLayoutableSizeConstrain(resolvedMin.height, resolvedExact.height, resolvedMax.height, &rangeMin.height, &rangeMax.height); - return {rangeMin, rangeMax}; -} - - #pragma mark - ASSizeRange +ASSizeRange ASSizeRangeMake(CGSize min, CGSize max) +{ + ASDisplayNodeCAssertPositiveReal(@"Range min width", min.width); + ASDisplayNodeCAssertPositiveReal(@"Range min height", min.height); + ASDisplayNodeCAssertInfOrPositiveReal(@"Range max width", max.width); + ASDisplayNodeCAssertInfOrPositiveReal(@"Range max height", max.height); + ASDisplayNodeCAssert(min.width <= max.width, + @"Range min width (%f) must not be larger than max width (%f).", min.width, max.width); + ASDisplayNodeCAssert(min.height <= max.height, + @"Range min height (%f) must not be larger than max height (%f).", min.height, max.height); + ASSizeRange sizeRange; sizeRange.min = min; sizeRange.max = max; return sizeRange; +} + +ASSizeRange ASSizeRangeMakeExactSize(CGSize size) +{ + return ASSizeRangeMake(size, size); +} + +CGSize ASSizeRangeClamp(ASSizeRange sizeRange, CGSize size) +{ + return CGSizeMake(MAX(sizeRange.min.width, MIN(sizeRange.max.width, size.width)), + MAX(sizeRange.min.height, MIN(sizeRange.max.height, size.height))); +} + struct _Range { CGFloat min; CGFloat max; @@ -201,17 +126,14 @@ ASSizeRange ASSizeRangeIntersect(ASSizeRange sizeRange, ASSizeRange otherSizeRan return {{w.min, h.min}, {w.max, h.max}}; } -NSString *NSStringFromASSizeRange(ASSizeRange sizeRange) +BOOL ASSizeRangeEqualToSizeRange(ASSizeRange lhs, ASSizeRange rhs) +{ + return CGSizeEqualToSize(lhs.min, rhs.min) && CGSizeEqualToSize(lhs.max, rhs.max); +} + +NSString * NSStringFromASSizeRange(ASSizeRange sizeRange) { return [NSString stringWithFormat:@"", NSStringFromCGSize(sizeRange.min), NSStringFromCGSize(sizeRange.max)]; } - - -#pragma mark - Deprecated - -ASSizeRange ASSizeRangeMakeExactSize(CGSize size) -{ - return ASSizeRangeMake(size); -} diff --git a/AsyncDisplayKit/Layout/ASInsetLayoutSpec.mm b/AsyncDisplayKit/Layout/ASInsetLayoutSpec.mm index 3c7f4985..9a6a3270 100644 --- a/AsyncDisplayKit/Layout/ASInsetLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASInsetLayoutSpec.mm @@ -67,15 +67,8 @@ static CGFloat centerInset(CGFloat outer, CGFloat inner) Inset will compute a new constrained size for it's child after applying insets and re-positioning the child to respect the inset. */ -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - restrictedToSize:(ASLayoutableSize)size - relativeToParentSize:(CGSize)parentSize +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { - if (self.child == nil) { - ASDisplayNodeAssert(NO, @"Inset spec measured without a child. The spec will do nothing."); - return [ASLayout layoutWithLayoutable:self size:CGSizeZero]; - } - const CGFloat insetsX = (finiteOrZero(_insets.left) + finiteOrZero(_insets.right)); const CGFloat insetsY = (finiteOrZero(_insets.top) + finiteOrZero(_insets.bottom)); @@ -95,12 +88,14 @@ static CGFloat centerInset(CGFloat outer, CGFloat inner) } }; - const CGSize insetParentSize = { - MAX(0, parentSize.width - insetsX), - MAX(0, parentSize.height - insetsY) - }; + if (self.child == nil) { + ASDisplayNodeAssert(NO, @"Inset spec measured without a child. The spec will do nothing."); + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:CGSizeZero]; + } - ASLayout *sublayout = [self.child layoutThatFits:insetConstrainedSize parentSize:insetParentSize]; + ASLayout *sublayout = [self.child measureWithSizeRange:insetConstrainedSize]; const CGSize computedSize = ASSizeRangeClamp(constrainedSize, { finite(sublayout.size.width + _insets.left + _insets.right, constrainedSize.max.width), @@ -118,7 +113,10 @@ static CGFloat centerInset(CGFloat outer, CGFloat inner) sublayout.position = CGPointMake(x, y); - return [ASLayout layoutWithLayoutable:self size:computedSize sublayouts:@[sublayout]]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:computedSize + sublayouts:@[sublayout]]; } @end diff --git a/AsyncDisplayKit/Layout/ASLayout.h b/AsyncDisplayKit/Layout/ASLayout.h index c5f66b21..31465987 100644 --- a/AsyncDisplayKit/Layout/ASLayout.h +++ b/AsyncDisplayKit/Layout/ASLayout.h @@ -17,29 +17,10 @@ NS_ASSUME_NONNULL_BEGIN -ASDISPLAYNODE_EXTERN_C_BEGIN - extern CGPoint const CGPointNull; extern BOOL CGPointIsNull(CGPoint point); -/** - * Safely calculates the layout of the given root layoutable by guarding against nil nodes. - * @param rootLayoutable The root node to calculate the layout for. - * @param sizeRange The size range to calculate the root layout within. - */ -extern ASLayout *ASCalculateRootLayout(id rootLayoutable, const ASSizeRange sizeRange); - -/** - * Safely computes the layout of the given node by guarding against nil nodes. - * @param component The component to calculate the layout for. - * @param sizeRange The size range to calculate the node layout within. - * @param parentSize The parent size of the node to calculate the layout for. - */ -extern ASLayout *ASCalculateLayout(id layoutable, const ASSizeRange sizeRange, const CGSize parentSize); - -ASDISPLAYNODE_EXTERN_C_END - /** * A node in the layout tree that represents the size and position of the object that created it (ASLayoutable). */ @@ -48,56 +29,68 @@ ASDISPLAYNODE_EXTERN_C_END /** * The underlying object described by this layout */ -@property (nonatomic, weak, readonly) id layoutable; +@property (nonatomic, weak, readonly) id layoutableObject; /** * The type of ASLayoutable that created this layout */ -@property (nonatomic, assign, readonly) ASLayoutableType type; +@property (nonatomic, readonly) ASLayoutableType type; /** * Size of the current layout */ -@property (nonatomic, assign, readonly) CGSize size; +@property (nonatomic, readonly) CGSize size; /** * Position in parent. Default to CGPointNull. * * @discussion When being used as a sublayout, this property must not equal CGPointNull. */ -@property (nonatomic, assign, readwrite) CGPoint position; +@property (nonatomic, readwrite) CGPoint position; + +/** + * The size range that was use to determine the size of the layout. + */ +@property (nonatomic, readonly) ASSizeRange constrainedSizeRange; /** * Array of ASLayouts. Each must have a valid non-null position. */ -@property (nonatomic, copy, readonly) NSArray *sublayouts; +@property (nonatomic, readonly) NSArray *sublayouts; + +/** + * Mark the layout dirty for future regeneration. + */ +@property (nonatomic, getter=isDirty) BOOL dirty; /** * @abstract Returns a valid frame for the current layout computed with the size and position. * @discussion Clamps the layout's origin or position to 0 if any of the calculated values are infinite. */ -@property (nonatomic, assign, readonly) CGRect frame; +@property (nonatomic, readonly) CGRect frame; /** * Designated initializer */ -- (instancetype)initWithLayoutable:(id)layoutable - size:(CGSize)size - position:(CGPoint)position - sublayouts:(nullable NSArray *)sublayouts NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size + position:(CGPoint)position + sublayouts:(NSArray *)sublayouts NS_DESIGNATED_INITIALIZER; /** * Convenience class initializer for layout construction. * - * @param layoutable The backing ASLayoutable object. + * @param layoutableObject The backing ASLayoutable object. * @param size The size of this layout. * @param position The position of this layout within its parent (if available). * @param sublayouts Sublayouts belong to the new layout. */ -+ (instancetype)layoutWithLayoutable:(id)layoutable - size:(CGSize)size - position:(CGPoint)position - sublayouts:(nullable NSArray *)sublayouts; ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size + position:(CGPoint)position + sublayouts:(nullable NSArray *)sublayouts; /** * Convenience initializer that has CGPointNull position. @@ -105,29 +98,43 @@ ASDISPLAYNODE_EXTERN_C_END * or for ASLayoutSpec subclasses that are referencing the "self" level in the layout tree, * or for creating a sublayout of which the position is yet to be determined. * - * @param layoutable The backing ASLayoutable object. - * @param size The size of this layout. - * @param sublayouts Sublayouts belong to the new layout. + * @param layoutableObject The backing ASLayoutable object. + * @param size The size of this layout. + * @param sublayouts Sublayouts belong to the new layout. */ -+ (instancetype)layoutWithLayoutable:(id)layoutable - size:(CGSize)size - sublayouts:(nullable NSArray *)sublayouts; ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size + sublayouts:(nullable NSArray *)sublayouts; /** - * Convenience that has CGPointNull position and no sublayouts. + * Convenience that has CGPointNull position and no sublayouts. * Best used for creating a layout that has no sublayouts, and is either a root one * or a sublayout of which the position is yet to be determined. * - * @param layoutable The backing ASLayoutable object. - * @param size The size of this layout. + * @param layoutableObject The backing ASLayoutable object. + * @param size The size of this layout. */ -+ (instancetype)layoutWithLayoutable:(id)layoutable - size:(CGSize)size; ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size; + +/** + * Convenience initializer that is flattened and has CGPointNull position. + * + * @param layoutableObject The backing ASLayoutable object. + * @param size The size of this layout. + * @param sublayouts Sublayouts belong to the new layout. + */ ++ (instancetype)flattenedLayoutWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size + sublayouts:(nullable NSArray *)sublayouts; + /** * Convenience initializer that creates a layout based on the values of the given layout, with a new position - * - * @param layout The layout to use to create the new layout - * @param position The position of the new layout + * @param layout The layout to use to create the new layout + * @param position The position of the new layout */ + (instancetype)layoutWithLayout:(ASLayout *)layout position:(CGPoint)position; @@ -138,14 +145,6 @@ ASDISPLAYNODE_EXTERN_C_END @end -@interface ASLayout (Unavailable) - -- (instancetype)init __unavailable; - -@end - -#pragma mark - Debugging - @interface ASLayout (Debugging) /** @@ -155,4 +154,10 @@ ASDISPLAYNODE_EXTERN_C_END @end +@interface ASLayout (Unavailable) + +- (instancetype)init __unavailable; + +@end + NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Layout/ASLayout.mm b/AsyncDisplayKit/Layout/ASLayout.mm index 42dc5ca3..575f593e 100644 --- a/AsyncDisplayKit/Layout/ASLayout.mm +++ b/AsyncDisplayKit/Layout/ASLayout.mm @@ -51,37 +51,38 @@ static inline NSString * descriptionIndents(NSUInteger indents) @dynamic frame, type; -- (instancetype)initWithLayoutable:(id)layoutable - size:(CGSize)size - position:(CGPoint)position - sublayouts:(nullable NSArray *)sublayouts +- (instancetype)initWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size + position:(CGPoint)position + sublayouts:(NSArray *)sublayouts { - NSParameterAssert(layoutable); - self = [super init]; if (self) { + NSParameterAssert(layoutableObject); #if DEBUG for (ASLayout *sublayout in sublayouts) { ASDisplayNodeAssert(CGPointIsNull(sublayout.position) == NO, @"Invalid position is not allowed in sublayout."); } #endif - _layoutable = layoutable; + _layoutableObject = layoutableObject; - if (!ASIsCGSizeValidForLayout(size)) { - ASDisplayNodeAssert(NO, @"layoutSize is invalid and unsafe to provide to Core Animation! Release configurations will force to 0, 0. Size = %@, node = %@", NSStringFromCGSize(size), layoutable); + if (!isValidForLayout(size.width) || !isValidForLayout(size.height)) { + ASDisplayNodeAssert(NO, @"layoutSize is invalid and unsafe to provide to Core Animation! Production will force to 0, 0. Size = %@, node = %@", NSStringFromCGSize(size), layoutableObject); size = CGSizeZero; } else { size = CGSizeMake(ASCeilPixelValue(size.width), ASCeilPixelValue(size.height)); } + _constrainedSizeRange = sizeRange; _size = size; + _dirty = NO; if (CGPointIsNull(position) == NO) { _position = CGPointMake(ASCeilPixelValue(position.x), ASCeilPixelValue(position.y)); } else { _position = position; } - _sublayouts = sublayouts != nil ? [sublayouts copy] : @[]; _flattened = NO; } @@ -96,41 +97,61 @@ static inline NSString * descriptionIndents(NSUInteger indents) #pragma mark - Class Constructors -+ (instancetype)layoutWithLayoutable:(id)layoutable - size:(CGSize)size - position:(CGPoint)position - sublayouts:(nullable NSArray *)sublayouts ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size + position:(CGPoint)position + sublayouts:(NSArray *)sublayouts { - return [[self alloc] initWithLayoutable:layoutable + return [[self alloc] initWithLayoutableObject:layoutableObject + constrainedSizeRange:sizeRange + size:size + position:position + sublayouts:sublayouts]; +} + ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size + sublayouts:(NSArray *)sublayouts +{ + return [self layoutWithLayoutableObject:layoutableObject + constrainedSizeRange:sizeRange size:size - position:position + position:CGPointNull sublayouts:sublayouts]; } -+ (instancetype)layoutWithLayoutable:(id)layoutable - size:(CGSize)size - sublayouts:(nullable NSArray *)sublayouts ++ (instancetype)layoutWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size { - return [self layoutWithLayoutable:layoutable - size:size - position:CGPointNull - sublayouts:sublayouts]; + return [self layoutWithLayoutableObject:layoutableObject + constrainedSizeRange:sizeRange + size:size + position:CGPointNull + sublayouts:nil]; } -+ (instancetype)layoutWithLayoutable:(id)layoutable size:(CGSize)size ++ (instancetype)flattenedLayoutWithLayoutableObject:(id)layoutableObject + constrainedSizeRange:(ASSizeRange)sizeRange + size:(CGSize)size + sublayouts:(nullable NSArray *)sublayouts { - return [self layoutWithLayoutable:layoutable - size:size - position:CGPointNull - sublayouts:nil]; + return [self layoutWithLayoutableObject:layoutableObject + constrainedSizeRange:sizeRange + size:size + position:CGPointNull + sublayouts:sublayouts]; } + (instancetype)layoutWithLayout:(ASLayout *)layout position:(CGPoint)position { - return [self layoutWithLayoutable:layout.layoutable - size:layout.size - position:position - sublayouts:layout.sublayouts]; + return [self layoutWithLayoutableObject:layout.layoutableObject + constrainedSizeRange:layout.constrainedSizeRange + size:layout.size + position:position + sublayouts:layout.sublayouts]; } #pragma mark - Layout Flattening @@ -165,14 +186,17 @@ static inline NSString * descriptionIndents(NSUInteger indents) } } - return [ASLayout layoutWithLayoutable:_layoutable size:_size sublayouts:flattenedSublayouts]; + return [ASLayout layoutWithLayoutableObject:_layoutableObject + constrainedSizeRange:_constrainedSizeRange + size:_size + sublayouts:flattenedSublayouts]; } #pragma mark - Accessors - (ASLayoutableType)type { - return _layoutable.layoutableType; + return _layoutableObject.layoutableType; } - (CGRect)frame @@ -207,8 +231,8 @@ static inline NSString * descriptionIndents(NSUInteger indents) - (NSString *)description { - return [NSString stringWithFormat:@"<, layoutable = %@, position = %@; size = %@;>", - self, self.layoutable, NSStringFromCGPoint(self.position), NSStringFromCGSize(self.size)/*, NSStringFromASSizeRange(self.constrainedSize)*/]; + return [NSString stringWithFormat:@"<, layoutable = %@, position = %@; size = %@; constrainedSizeRange = %@>", + self, self.layoutableObject, NSStringFromCGPoint(self.position), NSStringFromCGSize(self.size), NSStringFromASSizeRange(self.constrainedSizeRange)]; } - (NSString *)recursiveDescription @@ -229,18 +253,3 @@ static inline NSString * descriptionIndents(NSUInteger indents) } @end - -ASLayout *ASCalculateLayout(id layoutable, const ASSizeRange sizeRange, const CGSize parentSize) -{ - ASDisplayNodeCAssertNotNil(layoutable, @"Not valid layoutable passed in."); - - return [layoutable layoutThatFits:sizeRange parentSize:parentSize]; -} - -ASLayout *ASCalculateRootLayout(id rootLayoutable, const ASSizeRange sizeRange) -{ - ASLayout *layout = ASCalculateLayout(rootLayoutable, sizeRange, sizeRange.max); - // Here could specific verfication happen - return layout; -} - diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.h b/AsyncDisplayKit/Layout/ASLayoutSpec.h index 371d72c3..72d5b244 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.h @@ -13,9 +13,7 @@ NS_ASSUME_NONNULL_BEGIN -/** - * A layout spec is an immutable object that describes a layout, loosely inspired by React. - */ +/** A layout spec is an immutable object that describes a layout, loosely inspired by React. */ @interface ASLayoutSpec : NSObject /** @@ -90,28 +88,6 @@ NS_ASSUME_NONNULL_BEGIN @end -/** - * An ASLayoutSpec subclass that can wrap a ASLayoutable and calculates the layout of the child. - */ -@interface ASWrapperLayoutSpec : ASLayoutSpec - -/* - * Returns an ASWrapperLayoutSpec object with the given layoutable as child - */ -+ (instancetype)wrapperWithLayoutable:(id)layoutable; - -/* - * Returns an ASWrapperLayoutSpec object initialized with the given layoutable as child - */ -- (instancetype)initWithLayoutable:(id)layoutable NS_DESIGNATED_INITIALIZER;; - -/* - * Init not available for ASWrapperLayoutSpec - */ -- (instancetype)init __unavailable; - -@end - @interface ASLayoutSpec (Debugging) /** * Used by other layout specs to create ascii art debug strings diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 7c2371b7..4c66b3c1 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -11,7 +11,6 @@ #import "ASLayoutSpec.h" #import "ASAssert.h" -#import "ASInternalHelpers.h" #import "ASEnvironmentInternal.h" #import "ASLayout.h" @@ -25,46 +24,25 @@ typedef std::map, std::less> ASChildMap; @interface ASLayoutSpec() { - ASDN::RecursiveMutex __instanceLock__; - ASLayoutableSize _size; ASEnvironmentState _environmentState; + ASDN::RecursiveMutex __instanceLock__; ASChildMap _children; } @end @implementation ASLayoutSpec -// Dynamic properties for ASLayoutables -@dynamic layoutableType, size; -// Dynamic properties for sizing -@dynamic width, height, minWidth, maxWidth, minHeight, maxHeight; -// Dynamic properties for stack spec -@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender; -// Dynamic properties for static spec -@dynamic layoutPosition; - +// these dynamic properties all defined in ASLayoutOptionsPrivate.m +@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, + alignSelf, ascender, descender, sizeRange, layoutPosition, layoutableType; @synthesize isFinalLayoutable = _isFinalLayoutable; -#pragma mark - Class - -+ (void)initialize -{ - [super initialize]; - if (self != [ASLayoutSpec class]) { - ASDisplayNodeAssert(!ASSubclassOverridesSelector([ASLayoutSpec class], self, @selector(measureWithSizeRange:)), @"Subclass %@ must not override measureWithSizeRange: method. Instead overwrite calculateLayoutThatFits:", NSStringFromClass(self)); - } -} - - -#pragma mark - Lifecycle - - (instancetype)init { if (!(self = [super init])) { return nil; } _isMutable = YES; - _size = ASLayoutableSizeMake(); _environmentState = ASEnvironmentStateMakeDefault(); return self; } @@ -79,54 +57,13 @@ typedef std::map, std::less> ASCh return YES; } - -#pragma mark - Sizing - -- (ASLayoutableSize)size -{ - ASDN::MutexLocker l(__instanceLock__); - return _size; -} - -- (void)setSize:(ASLayoutableSize)size -{ - ASDN::MutexLocker l(__instanceLock__); - _size = size; -} - -ASLayoutableSizeForwarding -ASLayoutableSizeHelperForwarding - - #pragma mark - Layout -// Deprecated - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { - return [self layoutThatFits:constrainedSize]; -} - -- (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize -{ - return [self layoutThatFits:constrainedSize parentSize:constrainedSize.max]; -} - -- (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize parentSize:(CGSize)parentSize -{ - return [self calculateLayoutThatFits:constrainedSize restrictedToSize:_size relativeToParentSize:parentSize]; -} - -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - restrictedToSize:(ASLayoutableSize)size - relativeToParentSize:(CGSize)parentSize -{ - const ASSizeRange resolvedRange = ASSizeRangeIntersect(constrainedSize, ASLayoutableSizeResolve(_size, parentSize)); - return [self calculateLayoutThatFits:resolvedRange]; -} - -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize -{ - return [ASLayout layoutWithLayoutable:self size:constrainedSize.min]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:constrainedSize.min]; } - (id)finalLayoutable @@ -296,37 +233,6 @@ ASEnvironmentLayoutExtensibilityForwarding @end - -#pragma mark - ASWrapperLayoutSpec - -@implementation ASWrapperLayoutSpec - -+ (instancetype)wrapperWithLayoutable:(id)layoutable -{ - return [[self alloc] initWithLayoutable:layoutable]; -} - -- (instancetype)initWithLayoutable:(id)layoutable -{ - self = [super init]; - if (self) { - self.child = layoutable; - } - return self; -} - -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize -{ - ASLayout *sublayout = [self.child layoutThatFits:constrainedSize parentSize:constrainedSize.max]; - sublayout.position = CGPointZero; - return [ASLayout layoutWithLayoutable:self size:sublayout.size sublayouts:@[sublayout]]; -} - -@end - - -#pragma mark - ASLayoutSpec (Debugging) - @implementation ASLayoutSpec (Debugging) #pragma mark - ASLayoutableAsciiArtProtocol diff --git a/AsyncDisplayKit/Layout/ASLayoutValidation.mm b/AsyncDisplayKit/Layout/ASLayoutValidation.mm index 6f154542..1aa52133 100644 --- a/AsyncDisplayKit/Layout/ASLayoutValidation.mm +++ b/AsyncDisplayKit/Layout/ASLayoutValidation.mm @@ -65,14 +65,28 @@ static NSString *ASLayoutValidationWrappingAssertMessage(SEL selector, id obj, C - (void)validateLayout:(ASLayout *)layout { for (ASLayout *sublayout in layout.sublayouts) { - id layoutable = layout.layoutable; - id sublayoutLayoutable = sublayout.layoutable; + id layoutable = layout.layoutableObject; + id sublayoutLayoutable = sublayout.layoutableObject; NSString *assertMessage = nil; Class stackContainerClass = [ASStaticLayoutSpec class]; - // Check for default layoutPosition - if (!CGPointEqualToPoint(sublayoutLayoutable.layoutPosition, CGPointZero)) { + // Check for default sizeRange and layoutPosition + ASRelativeSizeRange sizeRange = sublayoutLayoutable.sizeRange; + ASRelativeSizeRange zeroSizeRange = ASRelativeSizeRangeMakeWithExactCGSize(CGSizeZero); + + // Currently setting the preferredFrameSize also updates the sizeRange. Create a size range based on the + // preferredFrameSize and check it if it's the same as the current sizeRange to be sure it was not changed manually + CGSize preferredFrameSize = CGSizeZero; + if ([sublayoutLayoutable respondsToSelector:@selector(preferredFrameSize)]) { + preferredFrameSize = [((ASDisplayNode *)sublayoutLayoutable) preferredFrameSize]; + } + ASRelativeSizeRange preferredFrameSizeRange = ASRelativeSizeRangeMakeWithExactCGSize(preferredFrameSize); + + if (ASRelativeSizeRangeEqualToRelativeSizeRange(sizeRange, zeroSizeRange) == NO && + ASRelativeSizeRangeEqualToRelativeSizeRange(sizeRange, preferredFrameSizeRange) == NO) { + assertMessage = ASLayoutValidationWrappingAssertMessage(@selector(sizeRange), sublayoutLayoutable, stackContainerClass); + } else if (!CGPointEqualToPoint(sublayoutLayoutable.layoutPosition, CGPointZero)) { assertMessage = ASLayoutValidationWrappingAssertMessage(@selector(layoutPosition), sublayoutLayoutable, stackContainerClass); } @@ -96,9 +110,9 @@ static NSString *ASLayoutValidationWrappingAssertMessage(SEL selector, id obj, C - (void)validateLayout:(ASLayout *)layout { - id layoutable = layout.layoutable; + id layoutable = layout.layoutableObject; for (ASLayout *sublayout in layout.sublayouts) { - id sublayoutLayoutable = sublayout.layoutable; + id sublayoutLayoutable = sublayout.layoutableObject; NSString *assertMessage = nil; Class stackContainerClass = [ASStackLayoutSpec class]; @@ -112,7 +126,7 @@ static NSString *ASLayoutValidationWrappingAssertMessage(SEL selector, id obj, C assertMessage = ASLayoutValidationWrappingAssertMessage(@selector(flexGrow), sublayoutLayoutable, stackContainerClass); } else if (sublayoutLayoutable.flexShrink == YES) { assertMessage = ASLayoutValidationWrappingAssertMessage(@selector(flexShrink), sublayoutLayoutable, stackContainerClass); - } else if (!ASDimensionEqualToDimension(sublayoutLayoutable.flexBasis, ASDimensionAuto) ) { + } else if (!ASRelativeDimensionEqualToRelativeDimension(sublayoutLayoutable.flexBasis, ASRelativeDimensionUnconstrained) ) { assertMessage = ASLayoutValidationWrappingAssertMessage(@selector(flexBasis), sublayoutLayoutable, stackContainerClass); } else if (sublayoutLayoutable.alignSelf != ASStackLayoutAlignSelfAuto) { assertMessage = ASLayoutValidationWrappingAssertMessage(@selector(alignSelf), sublayoutLayoutable, stackContainerClass); diff --git a/AsyncDisplayKit/Layout/ASLayoutable.h b/AsyncDisplayKit/Layout/ASLayoutable.h index deb0e303..ad1d1f8b 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.h +++ b/AsyncDisplayKit/Layout/ASLayoutable.h @@ -9,6 +9,7 @@ // #import +#import #import #import #import @@ -20,13 +21,6 @@ @class ASLayout; @class ASLayoutSpec; -/** A constant that indicates that the parent's size is not yet determined in a given dimension. */ -extern CGFloat const ASLayoutableParentDimensionUndefined; - -/** A constant that indicates that the parent's size is not yet determined in either dimension. */ -extern CGSize const ASLayoutableParentSizeUndefined; - -/** Type of ASLayoutable */ typedef NS_ENUM(NSUInteger, ASLayoutableType) { ASLayoutableTypeLayoutSpec, ASLayoutableTypeDisplayNode @@ -55,142 +49,24 @@ NS_ASSUME_NONNULL_BEGIN /** * @abstract Returns type of layoutable */ -@property (nonatomic, assign, readonly) ASLayoutableType layoutableType; +@property (nonatomic, readonly) ASLayoutableType layoutableType; /** * @abstract Returns if the layoutable can be used to layout in an asynchronous way on a background thread. */ -@property (nonatomic, assign, readonly) BOOL canLayoutAsynchronous; - -#pragma mark - Sizing +@property (nonatomic, readonly) BOOL canLayoutAsynchronous; /** - * @abstract The width property specifies the height of the content area of an ASLayoutable. - * The minWidth and maxWidth properties override width. - * Defaults to ASRelativeDimensionTypeAuto - */ -@property (nonatomic, assign, readwrite) ASDimension width; - -/** - * @abstract The height property specifies the height of the content area of an ASLayoutable - * The minHeight and maxHeight properties override height. - * Defaults to ASDimensionTypeAuto - */ -@property (nonatomic, assign, readwrite) ASDimension height; - -/** - * @abstract The minHeight property is used to set the minimum height of a given element. It prevents the used value - * of the height property from becoming smaller than the value specified for minHeight. - * The value of minHeight overrides both maxHeight and height. - * Defaults to ASDimensionTypeAuto - */ -@property (nonatomic, assign, readwrite) ASDimension minHeight; - -/** - * @abstract The maxHeight property is used to set the maximum height of an element. It prevents the used value of the - * height property from becoming larger than the value specified for maxHeight. - * The value of maxHeight overrides height, but minHeight overrides maxHeight. - * Defaults to ASDimensionTypeAuto - */ -@property (nonatomic, assign, readwrite) ASDimension maxHeight; - -/** - * @abstract The minWidth property is used to set the minimum width of a given element. It prevents the used value of - * the width property from becoming smaller than the value specified for minWidth. - * The value of minWidth overrides both maxWidth and width. - * Defaults to ASDimensionTypeAuto - */ -@property (nonatomic, assign, readwrite) ASDimension minWidth; - -/** - * @abstract The maxWidth property is used to set the maximum width of a given element. It prevents the used value of - * the width property from becoming larger than the value specified for maxWidth. - * The value of maxWidth overrides width, but minWidth overrides maxWidth. - * Defaults to ASDimensionTypeAuto - */ -@property (nonatomic, assign, readwrite) ASDimension maxWidth; - -/** - * @abstract Set max and width properties from given size - */ -- (void)setSizeWithCGSize:(CGSize)size; - -/** - * @abstract Set minHeight, maxHeight and minWidth, maxWidth properties from given size - */ -- (void)setExactSizeWithCGSize:(CGSize)size; - - -#pragma mark - Calculate layout - -/** - * @abstract Asks the node to return a layout based on given size range. + * @abstract Calculate a layout based on given size range. * * @param constrainedSize The minimum and maximum sizes the receiver should fit in. * - * @return An ASLayout instance defining the layout of the receiver (and its children, if the box layout model is used). - * - * @discussion Though this method does not set the bounds of the view, it does have side effects--caching both the - * constraint and the result. - * - * @warning Subclasses must not override this; it caches results from -calculateLayoutThatFits:. Calling this method may - * be expensive if result is not cached. - * - * @see [ASDisplayNode(Subclassing) calculateLayoutThatFits:] + * @return An ASLayout instance defining the layout of the receiver and its children. */ -- (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize; - -/** - * Call this on children layoutables to compute their layouts within your implementation of -calculateLayoutThatFits:. - * - * @warning You may not override this method. Override -calculateLayoutThatFits: instead. - * @warning In almost all cases, prefer the use of ASCalculateLayout in ASLayout - * - * @param constrainedSize Specifies a minimum and maximum size. The receiver must choose a size that is in this range. - * @param parentSize The parent node's size. If the parent component does not have a final size in a given dimension, - * then it should be passed as ASLayoutableParentDimensionUndefined (for example, if the parent's width - * depends on the child's size). - * - * @discussion Though this method does not set the bounds of the view, it does have side effects--caching both the - * constraint and the result. - * - * @return An ASLayout instance defining the layout of the receiver (and its children, if the box layout model is used). - */ -- (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize parentSize:(CGSize)parentSize; - -/** - * Override this method to compute your layoutable's layout. - * - * @discussion Why do you need to override -calculateLayoutThatFits: instead of -layoutThatFits:parentSize:? - * The base implementation of -layoutThatFits:parentSize: does the following for you: - * 1. First, it uses the parentSize parameter to resolve the nodes's size (the one assigned to the size property). - * 2. Then, it intersects the resolved size with the constrainedSize parameter. If the two don't intersect, - * constrainedSize wins. This allows a component to always override its childrens' sizes when computing its layout. - * (The analogy for UIView: you might return a certain size from -sizeThatFits:, but a parent view can always override - * that size and set your frame to any size.) - * 3. It caches it result for reuse - * - * @param constrainedSize A min and max size. This is computed as described in the description. The ASLayout you - * return MUST have a size between these two sizes. - */ -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize; - -/** - * In certain advanced cases, you may want to override this method. Overriding this method allows you to receive the - * layoutable's size, parentSize, and constrained size. With these values you could calculate the final constrained size - * and call -calculateLayoutThatFits: with the result. - * - * @warning Overriding this method should be done VERY rarely. - */ -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - restrictedToSize:(ASLayoutableSize)size - relativeToParentSize:(CGSize)parentSize; - - +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize; #pragma mark - Layout options from the Layoutable Protocols - #pragma mark - ASStackLayoutable /** * @abstract Additional space to place before this object in the stacking direction. @@ -218,10 +94,10 @@ NS_ASSUME_NONNULL_BEGIN /** * @abstract Specifies the initial size in the stack dimension for this object. - * Default to ASRelativeDimensionAuto + * Default to ASRelativeDimensionUnconstrained. * Used when attached to a stack layout. */ -@property (nonatomic, readwrite) ASDimension flexBasis; +@property (nonatomic, readwrite) ASRelativeDimension flexBasis; /** * @abstract Orientation of the object along cross axis, overriding alignItems @@ -239,28 +115,15 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, readwrite) CGFloat descender; - #pragma mark - ASStaticLayoutable - /** - * @abstract The position of this object within its parent spec. + If specified, the child's size is restricted according to this size. Fractions are resolved relative to the static layout spec. */ +@property (nonatomic, assign) ASRelativeSizeRange sizeRange; + +/** The position of this object within its parent spec. */ @property (nonatomic, assign) CGPoint layoutPosition; - -#pragma mark - Deprecated - -/** - * @abstract Calculate a layout based on given size range. - * - * @param constrainedSize The minimum and maximum sizes the receiver should fit in. - * - * @return An ASLayout instance defining the layout of the receiver and its children. - * - * @deprecated Deprecated in version 2.0: Use ASCalculateRootLayout or ASCalculateLayout instead - */ -- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize ASDISPLAYNODE_DEPRECATED; - @end NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Layout/ASLayoutable.mm b/AsyncDisplayKit/Layout/ASLayoutable.mm index e3a98909..de0f6e5c 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.mm +++ b/AsyncDisplayKit/Layout/ASLayoutable.mm @@ -16,9 +16,6 @@ #import -CGFloat const ASLayoutableParentDimensionUndefined = NAN; -CGSize const ASLayoutableParentSizeUndefined = {ASLayoutableParentDimensionUndefined, ASLayoutableParentDimensionUndefined}; - int32_t const ASLayoutableContextInvalidTransitionID = 0; int32_t const ASLayoutableContextDefaultTransitionID = ASLayoutableContextInvalidTransitionID + 1; diff --git a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h index a31405a6..36031ca9 100644 --- a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h +++ b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h @@ -8,7 +8,7 @@ // of patent rights can be found in the PATENTS file in the same directory. // -#import "ASDimension.h" +#import @class ASLayoutSpec; @protocol ASLayoutable; @@ -40,11 +40,6 @@ extern void ASLayoutableClearCurrentContext(); */ @protocol ASLayoutablePrivate -/** - * @abstract A size constraint that should apply to this ASLayoutable. - */ -@property (nonatomic, assign, readwrite) ASLayoutableSize size; - /** * @abstract This method can be used to give the user a chance to wrap an ASLayoutable in an ASLayoutSpec * just before it is added to a parent ASLayoutSpec. For example, if you wanted an ASTextNode that was always @@ -66,7 +61,9 @@ extern void ASLayoutableClearCurrentContext(); @end -#pragma mark - ASLayoutableForwarding + +#pragma mark - ASLayoutOptionsForwarding + /** * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties * in ASLayoutable that are used when a node or spec is used in a layout spec. @@ -79,103 +76,6 @@ extern void ASLayoutableClearCurrentContext(); * layoutSpec may require. */ -#pragma mark - ASLayoutableSizeForwarding - -#define ASLayoutableSizeForwarding \ -\ -- (ASDimension)width\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - return _size.width;\ -}\ -\ -- (void)setWidth:(ASDimension)width\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - _size.width = width;\ -}\ -\ -- (ASDimension)height\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - return _size.height;\ -}\ -\ -- (void)setHeight:(ASDimension)height\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - _size.height = height;\ -}\ -\ -- (ASDimension)minWidth\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - return _size.minWidth;\ -}\ -\ -- (void)setMinWidth:(ASDimension)minWidth\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - _size.minWidth = minWidth;\ -}\ -\ -- (ASDimension)maxWidth\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - return _size.maxWidth;\ -}\ -\ -- (void)setMaxWidth:(ASDimension)maxWidth\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - _size.maxWidth = maxWidth;\ -}\ -\ -- (ASDimension)minHeight\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - return _size.minHeight;\ -}\ -\ -- (void)setMinHeight:(ASDimension)minHeight\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - _size.minHeight = minHeight;\ -}\ -\ -- (ASDimension)maxHeight\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - return _size.maxHeight;\ -}\ -\ -- (void)setMaxHeight:(ASDimension)maxHeight\ -{\ - ASDN::MutexLocker l(__instanceLock__);\ - _size.maxHeight = maxHeight;\ -}\ - - -#pragma mark - ASLayoutableSizeHelperForwarding - -#define ASLayoutableSizeHelperForwarding \ -- (void)setSizeWithCGSize:(CGSize)size\ -{\ - self.width = ASDimensionMakeWithPoints(size.width);\ - self.height = ASDimensionMakeWithPoints(size.height);\ -}\ -\ -- (void)setExactSizeWithCGSize:(CGSize)size\ -{\ - self.minWidth = ASDimensionMakeWithPoints(size.width);\ - self.minHeight = ASDimensionMakeWithPoints(size.height);\ - self.maxWidth = ASDimensionMakeWithPoints(size.width);\ - self.maxHeight = ASDimensionMakeWithPoints(size.height);\ -}\ - - -#pragma mark - ASLayoutOptionsForwarding - #define ASEnvironmentLayoutOptionsForwarding \ - (void)propagateUpLayoutOptionsState\ {\ @@ -232,12 +132,12 @@ extern void ASLayoutableClearCurrentContext(); [self propagateUpLayoutOptionsState];\ }\ \ -- (ASDimension)flexBasis\ +- (ASRelativeDimension)flexBasis\ {\ return _environmentState.layoutOptionsState.flexBasis;\ }\ \ -- (void)setFlexBasis:(ASDimension)flexBasis\ +- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ {\ _environmentState.layoutOptionsState.flexBasis = flexBasis;\ [self propagateUpLayoutOptionsState];\ @@ -276,6 +176,17 @@ extern void ASLayoutableClearCurrentContext(); [self propagateUpLayoutOptionsState];\ }\ \ +- (ASRelativeSizeRange)sizeRange\ +{\ + return _environmentState.layoutOptionsState.sizeRange;\ +}\ +\ +- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ +{\ + _environmentState.layoutOptionsState.sizeRange = sizeRange;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ - (CGPoint)layoutPosition\ {\ return _environmentState.layoutOptionsState.layoutPosition;\ diff --git a/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm b/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm index 81a261bd..02f7b4d5 100644 --- a/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm @@ -47,21 +47,21 @@ static NSUInteger const kOverlayChildIndex = 1; /** First layout the contents, then fit the overlay on top of it. */ -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - restrictedToSize:(ASLayoutableSize)size - relativeToParentSize:(CGSize)parentSize +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { - ASLayout *contentsLayout = [self.child layoutThatFits:constrainedSize parentSize:parentSize]; + ASLayout *contentsLayout = [self.child measureWithSizeRange:constrainedSize]; contentsLayout.position = CGPointZero; NSMutableArray *sublayouts = [NSMutableArray arrayWithObject:contentsLayout]; if (self.overlay) { - ASLayout *overlayLayout = [self.overlay layoutThatFits:ASSizeRangeMake(contentsLayout.size) - parentSize:contentsLayout.size]; + ASLayout *overlayLayout = [self.overlay measureWithSizeRange:{contentsLayout.size, contentsLayout.size}]; overlayLayout.position = CGPointZero; [sublayouts addObject:overlayLayout]; } - return [ASLayout layoutWithLayoutable:self size:contentsLayout.size sublayouts:sublayouts]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:contentsLayout.size + sublayouts:sublayouts]; } @end diff --git a/AsyncDisplayKit/Layout/ASRatioLayoutSpec.mm b/AsyncDisplayKit/Layout/ASRatioLayoutSpec.mm index 1d7ab611..32e1bdea 100644 --- a/AsyncDisplayKit/Layout/ASRatioLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASRatioLayoutSpec.mm @@ -47,18 +47,16 @@ _ratio = ratio; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { std::vector sizeOptions; - // TODO: layout: isValidForLayout() call should not be necessary if INFINITY is used - if (!isinf(constrainedSize.max.width) && ASPointsAreValidForLayout(constrainedSize.max.width)) { + if (!isinf(constrainedSize.max.width)) { sizeOptions.push_back(ASSizeRangeClamp(constrainedSize, { constrainedSize.max.width, ASFloorPixelValue(_ratio * constrainedSize.max.width) })); } - // TODO: layout: isValidForLayout() call should not be necessary if INFINITY is used - if (!isinf(constrainedSize.max.height) && ASPointsAreValidForLayout(constrainedSize.max.width)) { + if (!isinf(constrainedSize.max.height)) { sizeOptions.push_back(ASSizeRangeClamp(constrainedSize, { ASFloorPixelValue(constrainedSize.max.height / _ratio), constrainedSize.max.height @@ -72,10 +70,12 @@ // If there is no max size in *either* dimension, we can't apply the ratio, so just pass our size range through. const ASSizeRange childRange = (bestSize == sizeOptions.end()) ? constrainedSize : ASSizeRangeMake(*bestSize, *bestSize); - const CGSize parentSize = (bestSize == sizeOptions.end()) ? ASLayoutableParentSizeUndefined : *bestSize; - ASLayout *sublayout = [self.child layoutThatFits:childRange parentSize:parentSize]; + ASLayout *sublayout = [self.child measureWithSizeRange:childRange]; sublayout.position = CGPointZero; - return [ASLayout layoutWithLayoutable:self size:sublayout.size sublayouts:@[sublayout]]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:sublayout.size + sublayouts:@[sublayout]]; } @end diff --git a/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm index 8907de72..d705297c 100644 --- a/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm @@ -52,15 +52,11 @@ _sizingOption = sizingOption; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { - // If we have a finite size in any direction, pass this so that the child can - // resolve percentages against it. Otherwise pass ASLayoutableParentDimensionUndefined - // as the size will depend on the content - // TODO: layout: isValidForLayout() call should not be necessary if INFINITY is used CGSize size = { - isinf(constrainedSize.max.width) || !ASPointsAreValidForLayout(constrainedSize.max.width) ? ASLayoutableParentDimensionUndefined : constrainedSize.max.width, - isinf(constrainedSize.max.height) || !ASPointsAreValidForLayout(constrainedSize.max.height) ? ASLayoutableParentDimensionUndefined : constrainedSize.max.height + constrainedSize.max.width, + constrainedSize.max.height }; BOOL reduceWidth = (_horizontalPosition & ASRelativeLayoutSpecPositionCenter) != 0 || @@ -74,8 +70,7 @@ reduceWidth ? 0 : constrainedSize.min.width, reduceHeight ? 0 : constrainedSize.min.height, }; - - ASLayout *sublayout = [self.child layoutThatFits:ASSizeRangeMake(minChildSize, constrainedSize.max) parentSize:size]; + 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 @@ -99,7 +94,10 @@ ASRoundPixelValue((size.height - sublayout.size.height) * yPosition) }; - return [ASLayout layoutWithLayoutable:self size:size sublayouts:@[sublayout]]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:size + sublayouts:@[sublayout]]; } - (CGFloat)proportionOfAxisForAxisPosition:(ASRelativeLayoutSpecPosition)position diff --git a/AsyncDisplayKit/Layout/ASRelativeSize.h b/AsyncDisplayKit/Layout/ASRelativeSize.h index 38c0a3b9..4f355044 100644 --- a/AsyncDisplayKit/Layout/ASRelativeSize.h +++ b/AsyncDisplayKit/Layout/ASRelativeSize.h @@ -8,4 +8,68 @@ // of patent rights can be found in the PATENTS file in the same directory. // -// TODO: layout: Remove file +#import +#import +#import + +/** + Expresses a size with relative dimensions. + Used by ASStaticLayoutSpec. + */ +typedef struct { + ASRelativeDimension width; + ASRelativeDimension height; +} ASRelativeSize; + +/** + Expresses an inclusive range of relative sizes. Used to provide additional constraint to layout. + Used by ASStaticLayoutSpec. + */ +typedef struct { + ASRelativeSize min; + ASRelativeSize max; +} ASRelativeSizeRange; + +extern ASRelativeSizeRange const ASRelativeSizeRangeUnconstrained; + +ASDISPLAYNODE_EXTERN_C_BEGIN +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - ASRelativeSize + +extern ASRelativeSize ASRelativeSizeMake(ASRelativeDimension width, ASRelativeDimension height); + +/** Convenience constructor to provide size in points. */ +extern ASRelativeSize ASRelativeSizeMakeWithCGSize(CGSize size); + +/** Convenience constructor to provide size as a fraction. */ +extern ASRelativeSize ASRelativeSizeMakeWithFraction(CGFloat fraction); + +/** Resolve this relative size relative to a parent size. */ +extern CGSize ASRelativeSizeResolveSize(ASRelativeSize relativeSize, CGSize parentSize); + +extern BOOL ASRelativeSizeEqualToRelativeSize(ASRelativeSize lhs, ASRelativeSize rhs); + +extern NSString *NSStringFromASRelativeSize(ASRelativeSize size); + +#pragma mark - ASRelativeSizeRange + +extern ASRelativeSizeRange ASRelativeSizeRangeMake(ASRelativeSize min, ASRelativeSize max); + +#pragma mark Convenience constructors to provide an exact size (min == max). +extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSize exact); + +extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact); + +extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactFraction(CGFloat fraction); + +extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth, + ASRelativeDimension exactHeight); + +extern BOOL ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRange lhs, ASRelativeSizeRange rhs); + +/** Provided a parent size, compute final dimensions for this RelativeSizeRange to arrive at a SizeRange. */ +extern ASSizeRange ASRelativeSizeRangeResolve(ASRelativeSizeRange relativeSizeRange, CGSize parentSize); + +NS_ASSUME_NONNULL_END +ASDISPLAYNODE_EXTERN_C_END diff --git a/AsyncDisplayKit/Layout/ASRelativeSize.mm b/AsyncDisplayKit/Layout/ASRelativeSize.mm index e43980af..3fc7abd9 100644 --- a/AsyncDisplayKit/Layout/ASRelativeSize.mm +++ b/AsyncDisplayKit/Layout/ASRelativeSize.mm @@ -8,4 +8,84 @@ // of patent rights can be found in the PATENTS file in the same directory. // -// TODO: layout: Remove file +#import "ASRelativeSize.h" + +ASRelativeSizeRange const ASRelativeSizeRangeUnconstrained = {}; + +#pragma mark - ASRelativeSize + +ASRelativeSize ASRelativeSizeMake(ASRelativeDimension width, ASRelativeDimension height) +{ + ASRelativeSize size; size.width = width; size.height = height; return size; +} + +ASRelativeSize ASRelativeSizeMakeWithCGSize(CGSize size) +{ + return ASRelativeSizeMake(ASRelativeDimensionMakeWithPoints(size.width), + ASRelativeDimensionMakeWithPoints(size.height)); +} + +ASRelativeSize ASRelativeSizeMakeWithFraction(CGFloat fraction) +{ + return ASRelativeSizeMake(ASRelativeDimensionMakeWithFraction(fraction), + ASRelativeDimensionMakeWithFraction(fraction)); +} + +CGSize ASRelativeSizeResolveSize(ASRelativeSize relativeSize, CGSize parentSize) +{ + return CGSizeMake(ASRelativeDimensionResolve(relativeSize.width, parentSize.width), + ASRelativeDimensionResolve(relativeSize.height, parentSize.height)); +} + +BOOL ASRelativeSizeEqualToRelativeSize(ASRelativeSize lhs, ASRelativeSize rhs) +{ + return ASRelativeDimensionEqualToRelativeDimension(lhs.width, rhs.width) + && ASRelativeDimensionEqualToRelativeDimension(lhs.height, rhs.height); +} + +NSString *NSStringFromASRelativeSize(ASRelativeSize size) +{ + return [NSString stringWithFormat:@"{%@, %@}", + NSStringFromASRelativeDimension(size.width), + NSStringFromASRelativeDimension(size.height)]; +} + +#pragma mark - ASRelativeSizeRange + +ASRelativeSizeRange ASRelativeSizeRangeMake(ASRelativeSize min, ASRelativeSize max) +{ + ASRelativeSizeRange sizeRange; sizeRange.min = min; sizeRange.max = max; return sizeRange; +} + +ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSize exact) +{ + return ASRelativeSizeRangeMake(exact, exact); +} + +ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact) +{ + return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithCGSize(exact)); +} + +ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactFraction(CGFloat fraction) +{ + return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithFraction(fraction)); +} + +ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth, + ASRelativeDimension exactHeight) +{ + return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMake(exactWidth, exactHeight)); +} + +BOOL ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRange lhs, ASRelativeSizeRange rhs) +{ + return ASRelativeSizeEqualToRelativeSize(lhs.min, rhs.min) && ASRelativeSizeEqualToRelativeSize(lhs.max, rhs.max); +} + +ASSizeRange ASRelativeSizeRangeResolve(ASRelativeSizeRange relativeSizeRange, + CGSize parentSize) +{ + return ASSizeRangeMake(ASRelativeSizeResolveSize(relativeSizeRange.min, parentSize), + ASRelativeSizeResolveSize(relativeSizeRange.max, parentSize)); +} diff --git a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm index 0486a867..0b74a163 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm @@ -118,7 +118,7 @@ _baselineRelativeArrangement = baselineRelativeArrangement; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { std::vector> stackChildren; for (id child in self.children) { @@ -126,7 +126,9 @@ } if (stackChildren.empty()) { - return [ASLayout layoutWithLayoutable:self size:constrainedSize.min]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:constrainedSize.min]; } ASStackLayoutSpecStyle style = {.direction = _direction, .spacing = _spacing, .justifyContent = _justifyContent, .alignItems = _alignItems, .baselineRelativeArrangement = _baselineRelativeArrangement}; @@ -159,7 +161,10 @@ sublayouts = [NSArray arrayWithObjects:&positionedLayout.sublayouts[0] count:positionedLayout.sublayouts.size()]; } - return [ASLayout layoutWithLayoutable:self size:ASSizeRangeClamp(constrainedSize, finalSize) sublayouts:sublayouts]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:ASSizeRangeClamp(constrainedSize, finalSize) + sublayouts:sublayouts]; } - (void)resolveHorizontalAlignment diff --git a/AsyncDisplayKit/Layout/ASStackLayoutable.h b/AsyncDisplayKit/Layout/ASStackLayoutable.h index 9932d527..ffd42511 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutable.h +++ b/AsyncDisplayKit/Layout/ASStackLayoutable.h @@ -44,10 +44,10 @@ NS_ASSUME_NONNULL_BEGIN /** * @abstract Specifies the initial size in the stack dimension for this object. - * Default to ASDimensionAuto + * Default to ASRelativeDimensionUnconstrained. * Used when attached to a stack layout. */ -@property (nonatomic, readwrite) ASDimension flexBasis; +@property (nonatomic, readwrite) ASRelativeDimension flexBasis; /** * @abstract Orientation of the object along cross axis, overriding alignItems diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.h b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.h index cdd85907..93450695 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.h @@ -9,6 +9,7 @@ // #import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm index e97eb651..516e79e7 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm @@ -34,46 +34,42 @@ return self; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize { - // TODO: layout: isValidForLayout() call should not be necessary if INFINITY is used - CGSize size = { - (isinf(constrainedSize.max.width) || !ASPointsAreValidForLayout(constrainedSize.max.width)) ? ASLayoutableParentDimensionUndefined : constrainedSize.max.width, - (isinf(constrainedSize.max.height) || !ASPointsAreValidForLayout(constrainedSize.max.height)) ? ASLayoutableParentDimensionUndefined : constrainedSize.max.height - }; + CGSize maxConstrainedSize = CGSizeMake(constrainedSize.max.width, constrainedSize.max.height); NSArray *children = self.children; NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:children.count]; for (id child in children) { CGPoint layoutPosition = child.layoutPosition; - CGSize autoMaxSize = { - constrainedSize.max.width - layoutPosition.x, - constrainedSize.max.height - layoutPosition.y - }; - - const ASSizeRange childConstraint = ASLayoutableSizeResolveAutoSize(child.size, size, {{0,0}, autoMaxSize}); + CGSize autoMaxSize = CGSizeMake(maxConstrainedSize.width - layoutPosition.x, + maxConstrainedSize.height - layoutPosition.y); - ASLayout *sublayout = [child layoutThatFits:childConstraint parentSize:size]; + ASRelativeSizeRange childSizeRange = child.sizeRange; + BOOL childIsUnconstrained = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, childSizeRange); + ASSizeRange childConstraint = childIsUnconstrained ? ASSizeRangeMake({0, 0}, autoMaxSize) + : ASRelativeSizeRangeResolve(childSizeRange, maxConstrainedSize); + + ASLayout *sublayout = [child measureWithSizeRange:childConstraint]; sublayout.position = layoutPosition; [sublayouts addObject:sublayout]; } - if (isnan(size.width)) { - size.width = constrainedSize.min.width; - for (ASLayout *sublayout in sublayouts) { - size.width = MAX(size.width, sublayout.position.x + sublayout.size.width); - } + CGSize size = CGSizeMake(constrainedSize.min.width, constrainedSize.min.height); + + for (ASLayout *sublayout in sublayouts) { + CGPoint sublayoutPosition = sublayout.position; + CGSize sublayoutSize = sublayout.size; + + size.width = MAX(size.width, sublayoutPosition.x + sublayoutSize.width); + size.height = MAX(size.height, sublayoutPosition.y + sublayoutSize.height); } - - if (isnan(size.height)) { - size.height = constrainedSize.min.height; - for (ASLayout *sublayout in sublayouts) { - size.height = MAX(size.height, sublayout.position.y + sublayout.size.height); - } - } - - return [ASLayout layoutWithLayoutable:self size:ASSizeRangeClamp(constrainedSize, size) sublayouts:sublayouts]; + + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:ASSizeRangeClamp(constrainedSize, size) + sublayouts:sublayouts]; } @end diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutable.h b/AsyncDisplayKit/Layout/ASStaticLayoutable.h index 955a9396..d1c3f748 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutable.h +++ b/AsyncDisplayKit/Layout/ASStaticLayoutable.h @@ -8,6 +8,8 @@ // of patent rights can be found in the PATENTS file in the same directory. // +#import + NS_ASSUME_NONNULL_BEGIN /** @@ -16,8 +18,11 @@ NS_ASSUME_NONNULL_BEGIN @protocol ASStaticLayoutable /** - * @abstract The position of this object within its parent spec. + If specified, the child's size is restricted according to this size. Fractions are resolved relative to the static layout spec. */ +@property (nonatomic, assign) ASRelativeSizeRange sizeRange; + +/** The position of this object within its parent spec. */ @property (nonatomic, assign) CGPoint layoutPosition; @end diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index 57555a8d..3e9bc398 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -43,6 +43,8 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) ASDisplayNodeMethodOverrideLayoutSpecThatFits = 1 << 4 }; +@class _ASDisplayNodePosition; + FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification; FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp; @@ -102,9 +104,6 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo @protected ASDisplayNode * __weak _supernode; - - ASLayoutableSize _size; - CGSize _preferredFrameSize; ASSentinel *_displaySentinel; @@ -115,20 +114,21 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo CGFloat _contentsScaleForDisplay; ASEnvironmentState _environmentState; + ASLayout *_calculatedLayout; + UIEdgeInsets _hitTestSlop; NSMutableArray *_subnodes; // Main thread only - BOOL _automaticallyManagesSubnodes; _ASTransitionContext *_pendingLayoutTransitionContext; + BOOL _automaticallyManagesSubnodes; NSTimeInterval _defaultLayoutTransitionDuration; NSTimeInterval _defaultLayoutTransitionDelay; UIViewAnimationOptions _defaultLayoutTransitionOptions; int32_t _pendingTransitionID; ASLayoutTransition *_pendingLayoutTransition; - std::shared_ptr _calculatedDisplayNodeLayout; ASDisplayNodeViewBlock _viewBlock; ASDisplayNodeLayerBlock _layerBlock; @@ -184,6 +184,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo // Swizzle to extend the builtin functionality with custom logic - (BOOL)__shouldLoadViewOrLayer; +- (BOOL)__shouldSize; /** Invoked before a call to setNeedsLayout to the underlying view diff --git a/AsyncDisplayKit/Private/ASDisplayNodeLayout.h b/AsyncDisplayKit/Private/ASDisplayNodeLayout.h deleted file mode 100644 index 64837acc..00000000 --- a/AsyncDisplayKit/Private/ASDisplayNodeLayout.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// ASDisplayNodeLayout.h -// AsyncDisplayKit -// -// Created by Michael Schneider on 08/26/16. -// -// 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. -// - -#pragma once - -#import "ASDimension.h" - -@class ASLayout; - -/* - * Represents a connection between an ASLayout and a ASDisplayNode - * ASDisplayNode uses this to store additional information that are necessary besides the layout - */ -struct ASDisplayNodeLayout { - ASLayout *layout; - ASSizeRange constrainedSize; - CGSize parentSize; - BOOL _dirty; - - /* - * Create a new display node layout with - * @param layout The layout to associate, usually returned from a call to -layoutThatFits:parentSize: - * @param constrainedSize Constrained size used to create the layout - * @param parentSize Parent size used to create the layout - */ - ASDisplayNodeLayout(ASLayout *layout, ASSizeRange constrainedSize, CGSize parentSize) - : layout(layout), constrainedSize(constrainedSize), parentSize(parentSize), _dirty(NO) {}; - - /* - * Creates a layout without any layout associated. By default this display node layout is dirty. - */ - ASDisplayNodeLayout() - : layout(nil), constrainedSize({{0, 0}, {0, 0}}), parentSize({0, 0}), _dirty(YES) {}; - - /** - * Returns if the display node layout is dirty as it was invalidated or it was created without a layout. - */ - BOOL isDirty(); - - /** - * Returns if ASDisplayNode is still valid for a given constrained and parent size - */ - BOOL isValidForConstrainedSizeParentSize(ASSizeRange constrainedSize, CGSize parentSize); - - /** - * Invalidate the display node layout - */ - void invalidate(); -}; diff --git a/AsyncDisplayKit/Private/ASDisplayNodeLayout.mm b/AsyncDisplayKit/Private/ASDisplayNodeLayout.mm deleted file mode 100644 index 3e536bdf..00000000 --- a/AsyncDisplayKit/Private/ASDisplayNodeLayout.mm +++ /dev/null @@ -1,34 +0,0 @@ -// -// ASDisplayNodeLayout.mm -// AsyncDisplayKit -// -// Created by Michael Schneider on 08/26/16. -// -// 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. -// - -#include "ASDisplayNodeLayout.h" - -BOOL ASDisplayNodeLayout::isDirty() -{ - return _dirty || layout == nil; -} - -BOOL ASDisplayNodeLayout::isValidForConstrainedSizeParentSize(ASSizeRange theConstrainedSize, CGSize theParentSize) -{ - // Only generate a new layout if: - // - The current layout is dirty - // - The passed constrained size is different than the original layout's parent or constrained size - return (layout != nil - && _dirty == NO - && CGSizeEqualToSize(parentSize, theParentSize) - && ASSizeRangeEqualToSizeRange(constrainedSize, theConstrainedSize)); -} - -void ASDisplayNodeLayout::invalidate() -{ - _dirty = YES; -} diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm index 84393f58..5a3c88b7 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -144,7 +144,7 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environme if (parentLayoutOptionsState.flexGrow == defaultState.flexGrow) { parentLayoutOptionsState.flexGrow = layoutOptionsState.flexGrow; } - if (ASDimensionEqualToDimension(parentLayoutOptionsState.flexBasis, defaultState.flexBasis)) { + if (ASRelativeDimensionEqualToRelativeDimension(parentLayoutOptionsState.flexBasis, defaultState.flexBasis)) { parentLayoutOptionsState.flexBasis = layoutOptionsState.flexBasis; } if (parentLayoutOptionsState.alignSelf == defaultState.alignSelf) { @@ -154,6 +154,10 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environme parentLayoutOptionsState.ascender = layoutOptionsState.ascender; } + if (ASRelativeSizeRangeEqualToRelativeSizeRange(parentLayoutOptionsState.sizeRange, defaultState.sizeRange)) { + // For now it is unclear if we should be up-propagating sizeRange or layoutPosition. + // parentLayoutOptionsState.sizeRange = layoutOptionsState.sizeRange; + } if (CGPointEqualToPoint(parentLayoutOptionsState.layoutPosition, defaultState.layoutPosition)) { // For now it is unclear if we should be up-propagating sizeRange or layoutPosition. // parentLayoutOptionsState.layoutPosition = layoutOptionsState.layoutPosition; diff --git a/AsyncDisplayKit/Private/ASInternalHelpers.h b/AsyncDisplayKit/Private/ASInternalHelpers.h index 54e7a1b1..4d2d82e9 100644 --- a/AsyncDisplayKit/Private/ASInternalHelpers.h +++ b/AsyncDisplayKit/Private/ASInternalHelpers.h @@ -9,6 +9,7 @@ // #import +#import #import diff --git a/AsyncDisplayKit/Private/ASLayoutTransition.h b/AsyncDisplayKit/Private/ASLayoutTransition.h index e6f37eab..64869dc0 100644 --- a/AsyncDisplayKit/Private/ASLayoutTransition.h +++ b/AsyncDisplayKit/Private/ASLayoutTransition.h @@ -12,13 +12,9 @@ #import "ASDimension.h" #import "_ASTransitionContext.h" -#import "ASDisplayNodeLayout.h" - -#import - -NS_ASSUME_NONNULL_BEGIN @class ASDisplayNode; +@class ASLayout; @interface ASLayoutTransition : NSObject <_ASTransitionContextLayoutDelegate> @@ -30,12 +26,12 @@ NS_ASSUME_NONNULL_BEGIN /** * Previous layout to transition from */ -@property (nonatomic, readonly, assign) std::shared_ptr previousLayout; +@property (nonatomic, readonly, strong) ASLayout *previousLayout; /** * Pending layout to transition to */ -@property (nonatomic, readonly, assign) std::shared_ptr pendingLayout; +@property (nonatomic, readonly, strong) ASLayout *pendingLayout; /** * Returns if the layout transition needs to happen synchronously @@ -45,9 +41,8 @@ NS_ASSUME_NONNULL_BEGIN /** * Returns a newly initialized layout transition */ -- (instancetype)initWithNode:(ASDisplayNode *)node - pendingLayout:(std::shared_ptr)pendingLayout - previousLayout:(std::shared_ptr)previousLayout NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithNode:(ASDisplayNode *)node pendingLayout:(ASLayout *)pendingLayout previousLayout:(ASLayout *)previousLayout NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; /** * Insert and remove subnodes that where added or removed between the previousLayout and the pendingLayout @@ -65,11 +60,3 @@ NS_ASSUME_NONNULL_BEGIN - (void)applySubnodeRemovals; @end - -@interface ASLayoutTransition (Unavailable) - -- (instancetype)init __unavailable; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Private/ASLayoutTransition.mm b/AsyncDisplayKit/Private/ASLayoutTransition.mm index 90357a26..52af19fa 100644 --- a/AsyncDisplayKit/Private/ASLayoutTransition.mm +++ b/AsyncDisplayKit/Private/ASLayoutTransition.mm @@ -34,7 +34,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { layout = queue.front(); queue.pop(); - if (layout.layoutable.canLayoutAsynchronous == NO) { + if (layout.layoutableObject.canLayoutAsynchronous == NO) { return NO; } @@ -58,8 +58,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { } - (instancetype)initWithNode:(ASDisplayNode *)node - pendingLayout:(std::shared_ptr)pendingLayout - previousLayout:(std::shared_ptr)previousLayout + pendingLayout:(ASLayout *)pendingLayout + previousLayout:(ASLayout *)previousLayout { self = [super init]; if (self) { @@ -72,16 +72,10 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { return self; } -- (instancetype)init -{ - ASDisplayNodeAssert(NO, @"Use the designated initializer"); - return [self init]; -} - - (BOOL)isSynchronous { ASDN::MutexSharedLocker l(__instanceLock__); - return !ASLayoutCanTransitionAsynchronous(_pendingLayout->layout); + return !ASLayoutCanTransitionAsynchronous(_pendingLayout); } - (void)commitTransition @@ -118,27 +112,23 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { if (_calculatedSubnodeOperations) { return; } - - ASLayout *previousLayout = _previousLayout->layout; - ASLayout *pendingLayout = _pendingLayout->layout; - - if (previousLayout) { + if (_previousLayout) { NSIndexSet *insertions, *deletions; - [previousLayout.sublayouts asdk_diffWithArray:pendingLayout.sublayouts - insertions:&insertions - deletions:&deletions - compareBlock:^BOOL(ASLayout *lhs, ASLayout *rhs) { - return ASObjectIsEqual(lhs.layoutable, rhs.layoutable); - }]; - findNodesInLayoutAtIndexes(pendingLayout, insertions, &_insertedSubnodes, &_insertedSubnodePositions); - findNodesInLayoutAtIndexesWithFilteredNodes(previousLayout, - deletions, - _insertedSubnodes, - &_removedSubnodes, - &_removedSubnodePositions); + [_previousLayout.sublayouts asdk_diffWithArray:_pendingLayout.sublayouts + insertions:&insertions + deletions:&deletions + compareBlock:^BOOL(ASLayout *lhs, ASLayout *rhs) { + return ASObjectIsEqual(lhs.layoutableObject, rhs.layoutableObject); + }]; + findNodesInLayoutAtIndexes(_pendingLayout, insertions, &_insertedSubnodes, &_insertedSubnodePositions); + findNodesInLayoutAtIndexesWithFilteredNodes(_previousLayout, + deletions, + _insertedSubnodes, + &_removedSubnodes, + &_removedSubnodePositions); } else { - NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pendingLayout.sublayouts count])]; - findNodesInLayoutAtIndexes(pendingLayout, indexes, &_insertedSubnodes, &_insertedSubnodePositions); + NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_pendingLayout.sublayouts count])]; + findNodesInLayoutAtIndexes(_pendingLayout, indexes, &_insertedSubnodes, &_insertedSubnodePositions); _removedSubnodes = nil; } _calculatedSubnodeOperations = YES; @@ -170,9 +160,9 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { { ASDN::MutexSharedLocker l(__instanceLock__); if ([key isEqualToString:ASTransitionContextFromLayoutKey]) { - return _previousLayout->layout; + return _previousLayout; } else if ([key isEqualToString:ASTransitionContextToLayoutKey]) { - return _pendingLayout->layout; + return _pendingLayout; } else { return nil; } @@ -182,9 +172,9 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { { ASDN::MutexSharedLocker l(__instanceLock__); if ([key isEqualToString:ASTransitionContextFromLayoutKey]) { - return _previousLayout->constrainedSize; + return _previousLayout.constrainedSizeRange; } else if ([key isEqualToString:ASTransitionContextToLayoutKey]) { - return _pendingLayout->constrainedSize; + return _pendingLayout.constrainedSizeRange; } else { return ASSizeRangeMake(CGSizeZero, CGSizeZero); } @@ -222,7 +212,7 @@ static inline void findNodesInLayoutAtIndexesWithFilteredNodes(ASLayout *layout, for (ASLayout *sublayout in layout.sublayouts) { if (idx > lastIndex) { break; } if (idx >= firstIndex && [indexes containsIndex:idx]) { - ASDisplayNode *node = (ASDisplayNode *)sublayout.layoutable; + ASDisplayNode *node = (ASDisplayNode *)sublayout.layoutableObject; ASDisplayNodeCAssert(node, @"A flattened layout must consist exclusively of node sublayouts"); // Ignore the odd case in which a non-node sublayout is accessed and the type cast fails if (node != nil) { diff --git a/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm b/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm index 57a5c6f2..4dc3e194 100644 --- a/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm @@ -15,7 +15,7 @@ static CGFloat baselineForItem(const ASStackLayoutSpecStyle &style, const ASLayout *layout) { - __weak id child = layout.layoutable; + __weak id child = layout.layoutableObject; switch (style.alignItems) { case ASStackLayoutAlignItemsBaselineFirst: return child.ascender; @@ -33,7 +33,7 @@ static CGFloat baselineOffset(const ASStackLayoutSpecStyle &style, const CGFloat maxBaseline) { if (style.direction == ASStackLayoutDirectionHorizontal) { - __weak id child = l.layoutable; + __weak id child = l.layoutableObject; switch (style.alignItems) { case ASStackLayoutAlignItemsBaselineFirst: return maxAscender - child.ascender; @@ -89,9 +89,9 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A our layoutSpec to have it so that it can be baseline aligned with another text node or baseline layout spec. */ const auto ascenderIt = std::max_element(positionedLayout.sublayouts.begin(), positionedLayout.sublayouts.end(), [&](const ASLayout *a, const ASLayout *b){ - return a.layoutable.ascender < b.layoutable.ascender; + return a.layoutableObject.ascender < b.layoutableObject.ascender; }); - const CGFloat maxAscender = ascenderIt == positionedLayout.sublayouts.end() ? 0 : (*ascenderIt).layoutable.ascender; + const CGFloat maxAscender = ascenderIt == positionedLayout.sublayouts.end() ? 0 : (*ascenderIt).layoutableObject.ascender; /* Step 3: Take each child and update its layout position based on the baseline offset. @@ -108,7 +108,7 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A CGPoint p = CGPointZero; BOOL first = YES; stackedChildren = AS::map(positionedLayout.sublayouts, [&](ASLayout *l) -> ASLayout *{ - __weak id child = l.layoutable; + __weak id child = l.layoutableObject; p = p + directionPoint(style.direction, child.spacingBefore, 0); if (first) { // if this is the first item use the previously computed start point @@ -161,7 +161,7 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A const auto descenderIt = std::max_element(stackedChildren.begin(), stackedChildren.end(), [&](const ASLayout *a, const ASLayout *b){ return a.position.y + a.size.height < b.position.y + b.size.height; }); - const CGFloat minDescender = descenderIt == stackedChildren.end() ? 0 : (*descenderIt).layoutable.descender; + const CGFloat minDescender = descenderIt == stackedChildren.end() ? 0 : (*descenderIt).layoutableObject.descender; return {stackedChildren, crossSize, maxAscender, minDescender}; } diff --git a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm index cabd487c..0dfa11fb 100644 --- a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm @@ -23,16 +23,15 @@ static ASLayout *crossChildLayout(const id child, const CGFloat stackMin, const CGFloat stackMax, const CGFloat crossMin, - const CGFloat crossMax, - const CGSize size) + const CGFloat crossMax) { const ASStackLayoutAlignItems alignItems = alignment(child.alignSelf, style.alignItems); // stretched children will have a cross dimension of at least crossMin const CGFloat childCrossMin = alignItems == ASStackLayoutAlignItemsStretch ? crossMin : 0; const ASSizeRange childSizeRange = directionSizeRange(style.direction, stackMin, stackMax, childCrossMin, crossMax); - ASLayout *layout = [child layoutThatFits:childSizeRange parentSize:size]; + ASLayout *layout = [child measureWithSizeRange:childSizeRange]; ASDisplayNodeCAssertNotNil(layout, @"ASLayout returned from measureWithSizeRange: must not be nil: %@", child); - return layout ? : [ASLayout layoutWithLayoutable:child size:{0, 0}]; + return layout ? : [ASLayout layoutWithLayoutableObject:child constrainedSizeRange:childSizeRange size:CGSizeZero]; } /** @@ -68,8 +67,7 @@ static ASLayout *crossChildLayout(const id child, @param style the layout style of the overall stack layout */ static void stretchChildrenAlongCrossDimension(std::vector &layouts, - const ASStackLayoutSpecStyle &style, - const CGSize size) + const ASStackLayoutSpecStyle &style) { // Find the maximum cross dimension size among child layouts const auto it = std::max_element(layouts.begin(), layouts.end(), @@ -79,16 +77,19 @@ static void stretchChildrenAlongCrossDimension(std::vectorlayout.size); for (auto &l : layouts) { - const ASStackLayoutAlignItems alignItems = alignment(l.child.alignSelf, style.alignItems); + const id child = l.child; + const CGSize size = l.layout.size; + + const ASStackLayoutAlignItems alignItems = alignment(child.alignSelf, style.alignItems); - const CGFloat cross = crossDimension(style.direction, l.layout.size); - const CGFloat stack = stackDimension(style.direction, l.layout.size); + const CGFloat cross = crossDimension(style.direction, size); + const CGFloat stack = stackDimension(style.direction, size); // restretch all stretchable children along the cross axis using the new min. set their max size to childCrossMax, // not crossMax, so that if any of them would choose a larger size just because the min size increased (weird!) // they are forced to choose the same width as all the other children. if (alignItems == ASStackLayoutAlignItemsStretch && std::fabs(cross - childCrossMax) > 0.01) { - l.layout = crossChildLayout(l.child, style, stack, stack, childCrossMax, childCrossMax, size); + l.layout = crossChildLayout(child, style, stack, stack, childCrossMax, childCrossMax); } } } @@ -216,8 +217,7 @@ ASDISPLAYNODE_INLINE BOOL useOptimizedFlexing(const std::vector */ static void layoutFlexibleChildrenAtZeroSize(std::vector &items, const ASStackLayoutSpecStyle &style, - const ASSizeRange &sizeRange, - const CGSize size) + const ASSizeRange &sizeRange) { for (ASStackUnpositionedItem &item : items) { const id child = item.child; @@ -227,8 +227,7 @@ static void layoutFlexibleChildrenAtZeroSize(std::vector &items, const ASStackLayoutSpecStyle &style, const ASSizeRange &sizeRange, - const CGSize size, const BOOL useOptimizedFlexing) { const CGFloat stackDimensionSum = computeStackDimensionSum(items, style); @@ -260,7 +258,7 @@ static void flexChildrenAlongStackDimension(std::vector if (flexibleChildren == 0) { // If optimized flexing was used then we have to clean up the unsized children, and lay them out at zero size if (useOptimizedFlexing) { - layoutFlexibleChildrenAtZeroSize(items, style, sizeRange, size); + layoutFlexibleChildrenAtZeroSize(items, style, sizeRange); } return; } @@ -282,8 +280,7 @@ static void flexChildrenAlongStackDimension(std::vector MAX(flexedStackSize, 0), MAX(flexedStackSize, 0), crossDimension(style.direction, sizeRange.min), - crossDimension(style.direction, sizeRange.max), - size); + crossDimension(style.direction, sizeRange.max)); isFirstFlex = NO; } } @@ -301,19 +298,23 @@ static std::vector layoutChildrenAlongUnconstrainedStac { const CGFloat minCrossDimension = crossDimension(style.direction, sizeRange.min); const CGFloat maxCrossDimension = crossDimension(style.direction, sizeRange.max); + return AS::map(children, [&](id child) -> ASStackUnpositionedItem { + const ASRelativeDimension flexBasis = child.flexBasis; + const BOOL isUnconstrainedFlexBasis = ASRelativeDimensionEqualToRelativeDimension(ASRelativeDimensionUnconstrained, flexBasis); + const CGFloat exactStackDimension = ASRelativeDimensionResolve(flexBasis, stackDimension(style.direction, size)); + if (useOptimizedFlexing && isFlexibleInBothDirections(child)) { - return { child, [ASLayout layoutWithLayoutable:child size:{0, 0}] }; + return { child, [ASLayout layoutWithLayoutableObject:child constrainedSizeRange:sizeRange size:{0, 0}] }; } else { return { child, crossChildLayout(child, style, - ASDimensionResolve(child.flexBasis, stackDimension(style.direction, size), 0), - ASDimensionResolve(child.flexBasis, stackDimension(style.direction, size), INFINITY), + isUnconstrainedFlexBasis ? 0 : exactStackDimension, + isUnconstrainedFlexBasis ? INFINITY : exactStackDimension, minCrossDimension, - maxCrossDimension, - size) + maxCrossDimension) }; } }); @@ -323,11 +324,9 @@ ASStackUnpositionedLayout ASStackUnpositionedLayout::compute(const std::vector _constrainedSize.width) { diff --git a/AsyncDisplayKit/_ASTransitionContext.m b/AsyncDisplayKit/_ASTransitionContext.m index 750d6806..03181040 100644 --- a/AsyncDisplayKit/_ASTransitionContext.m +++ b/AsyncDisplayKit/_ASTransitionContext.m @@ -65,7 +65,7 @@ NSString * const ASTransitionContextToLayoutKey = @"org.asyncdisplaykit.ASTransi - (CGRect)finalFrameForNode:(ASDisplayNode *)node { for (ASLayout *layout in [self layoutForKey:ASTransitionContextToLayoutKey].sublayouts) { - if (layout.layoutable == node) { + if (layout.layoutableObject == node) { return [layout frame]; } } @@ -76,7 +76,7 @@ NSString * const ASTransitionContextToLayoutKey = @"org.asyncdisplaykit.ASTransi { NSMutableArray *subnodes = [NSMutableArray array]; for (ASLayout *sublayout in [self layoutForKey:key].sublayouts) { - [subnodes addObject:(ASDisplayNode *)sublayout.layoutable]; + [subnodes addObject:(ASDisplayNode *)sublayout.layoutableObject]; } return subnodes; } diff --git a/AsyncDisplayKitTests/ASBackgroundLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASBackgroundLayoutSpecSnapshotTests.mm index 7775a3a7..54e12d98 100644 --- a/AsyncDisplayKitTests/ASBackgroundLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASBackgroundLayoutSpecSnapshotTests.mm @@ -24,7 +24,8 @@ static const ASSizeRange kSize = {{320, 320}, {320, 320}}; - (void)testBackground { ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor blackColor], {20, 20}); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor blackColor]); + foregroundNode.staticSize = {20, 20}; ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec diff --git a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm index 62c8dc85..406b25f6 100644 --- a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm @@ -45,16 +45,10 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}}; sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions { ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], CGSizeMake(70, 100)); + 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 @@ -89,23 +83,11 @@ static NSString *suffixForCenteringOptions(ASCenterLayoutSpecCenteringOptions ce - (void)testMinimumSizeRangeIsGivenToChildWhenNotCentering { ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor], CGSizeMake(10, 10)); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + 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/ASDisplayNodeImplicitHierarchyTests.m b/AsyncDisplayKitTests/ASDisplayNodeImplicitHierarchyTests.m index 95ba170b..1d5f0a00 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeImplicitHierarchyTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeImplicitHierarchyTests.m @@ -77,7 +77,7 @@ return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[stack1, stack2, node5]]; }; - [node layoutThatFits:ASSizeRangeMake(CGSizeZero)]; + [node measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeZero)]; XCTAssertEqual(node.subnodes[0], node5); XCTAssertEqual(node.subnodes[1], node1); XCTAssertEqual(node.subnodes[2], node2); @@ -104,13 +104,13 @@ } }; - [node layoutThatFits:ASSizeRangeMake(CGSizeZero)]; + [node measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeZero)]; XCTAssertEqual(node.subnodes[0], node1); XCTAssertEqual(node.subnodes[1], node2); node.layoutState = @2; [node invalidateCalculatedLayout]; - [node layoutThatFits:ASSizeRangeMake(CGSizeZero)]; + [node measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeZero)]; XCTAssertEqual(node.subnodes[0], node1); XCTAssertEqual(node.subnodes[1], node3); @@ -157,12 +157,12 @@ dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [node layoutThatFits:ASSizeRangeMake(CGSizeZero)]; + [node measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeZero)]; XCTAssertEqual(node.subnodes[0], node1); node.layoutState = @2; [node invalidateCalculatedLayout]; - [node layoutThatFits:ASSizeRangeMake(CGSizeZero)]; + [node measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeZero)]; // Dispatch back to the main thread to let the insertion / deletion of subnodes happening dispatch_async(dispatch_get_main_queue(), ^{ @@ -202,7 +202,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"Fix IHM layout transition also if one node is already loaded"]; - [node layoutThatFits:ASSizeRangeMake(CGSizeZero)]; + [node measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeZero)]; XCTAssertEqual(node.subnodes[0], node1); node.layoutState = @2; diff --git a/AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm b/AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm index 9b38bf5f..a2156291 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm +++ b/AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm @@ -22,9 +22,8 @@ { CGSize nodeSize = CGSizeMake(100, 100); - ASDisplayNode *displayNode = [[ASDisplayNode alloc] init]; - displayNode.width = ASDimensionMake(100); - displayNode.height = ASDimensionMake(100); + ASStaticSizeDisplayNode *displayNode = [ASStaticSizeDisplayNode new]; + displayNode.staticSize = nodeSize; // Use a button node in here as ASButtonNode uses layoutSpecThatFits: ASButtonNode *buttonNode = [ASButtonNode new]; @@ -48,8 +47,8 @@ { CGSize nodeSize = CGSizeMake(100, 100); - ASDisplayNode *displayNode = [ASDisplayNode new]; - [displayNode setSizeWithCGSize:nodeSize]; + ASStaticSizeDisplayNode *displayNode = [ASStaticSizeDisplayNode new]; + displayNode.staticSize = nodeSize; ASButtonNode *buttonNode = [ASButtonNode new]; [displayNode addSubnode:buttonNode]; @@ -80,7 +79,7 @@ return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:someOtherNode]; }; - XCTAssertThrows([displayNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))], @"Should throw if subnode was added in layoutSpecThatFits:"); + XCTAssertThrows([displayNode measure:CGSizeMake(100, 100)], @"Should throw if subnode was added in layoutSpecThatFits:"); } - (void)testNotAllowModifyingSubnodesInLayoutSpecThatFits @@ -96,7 +95,7 @@ return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:someOtherNode]; }; - XCTAssertThrows([displayNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))], @"Should throw if subnodes where modified in layoutSpecThatFits:"); + XCTAssertThrows([displayNode measure:CGSizeMake(100, 100)], @"Should throw if subnodes where modified in layoutSpecThatFits:"); } #endif @@ -104,8 +103,8 @@ { CGSize nodeSize = CGSizeMake(100, 100); - ASDisplayNode *displayNode = [ASDisplayNode new]; - [displayNode setSizeWithCGSize:nodeSize]; + ASStaticSizeDisplayNode *displayNode = [ASStaticSizeDisplayNode new]; + displayNode.staticSize = nodeSize; ASButtonNode *buttonNode = [ASButtonNode new]; [displayNode addSubnode:buttonNode]; @@ -122,7 +121,7 @@ [displayNode.view layoutIfNeeded]; XCTAssertEqual(numberOfLayoutSpecThatFitsCalls, 1, @"Should measure during layout if not measured"); - [displayNode layoutThatFits:ASSizeRangeMake(nodeSize, nodeSize)]; + [displayNode measureWithSizeRange:ASSizeRangeMake(nodeSize, nodeSize)]; XCTAssertEqual(numberOfLayoutSpecThatFitsCalls, 1, @"Should not remeasure with same bounds"); } diff --git a/AsyncDisplayKitTests/ASDisplayNodeSnapshotTests.m b/AsyncDisplayKitTests/ASDisplayNodeSnapshotTests.m index 2c2286b0..68f3c5b4 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeSnapshotTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeSnapshotTests.m @@ -28,7 +28,7 @@ node.layoutSpecBlock = ^(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) { return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(5, 5, 5, 5) child:subnode]; }; - [node layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))]; + [node measure:CGSizeMake(100, 100)]; ASSnapshotVerifyNode(node, nil); } diff --git a/AsyncDisplayKitTests/ASDisplayNodeTests.m b/AsyncDisplayKitTests/ASDisplayNodeTests.m index dfe8d470..583ff1fb 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeTests.m @@ -1991,7 +1991,7 @@ static bool stringContainsPointer(NSString *description, id p) { - (void)DISABLED_testThatItsSafeToAutomeasureANodeMidTransition { ASDisplayNode *supernode = [[ASDisplayNode alloc] init]; - [supernode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))]; + [supernode measure:CGSizeMake(100, 100)]; ASDisplayNode *node = [[ASDisplayNode alloc] init]; node.bounds = CGRectMake(0, 0, 50, 50); [supernode addSubnode:node]; diff --git a/AsyncDisplayKitTests/ASEditableTextNodeTests.m b/AsyncDisplayKitTests/ASEditableTextNodeTests.m index 7ac4ad50..83960f73 100644 --- a/AsyncDisplayKitTests/ASEditableTextNodeTests.m +++ b/AsyncDisplayKitTests/ASEditableTextNodeTests.m @@ -11,7 +11,6 @@ // #import -#import #import static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) @@ -139,11 +138,23 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) XCTAssertTrue(secureEditableTextNode.textView.secureTextEntry == YES, @"textView's isSecureTextEntry should be YES."); } +- (void)testSetPreferredFrameSize +{ + CGSize preferredFrameSize = CGSizeMake(100, 100); + _editableTextNode.preferredFrameSize = preferredFrameSize; + + CGSize calculatedSize = [_editableTextNode measure:CGSizeZero]; + XCTAssertTrue(calculatedSize.width != preferredFrameSize.width, @"Calculated width (%f) should be equal to preferred width (%f)", calculatedSize.width, preferredFrameSize.width); + XCTAssertTrue(calculatedSize.width != preferredFrameSize.width, @"Calculated height (%f) should be equal to preferred height (%f)", calculatedSize.width, preferredFrameSize.width); + + _editableTextNode.preferredFrameSize = CGSizeZero; +} + - (void)testCalculatedSizeIsGreaterThanOrEqualToConstrainedSize { for (NSInteger i = 10; i < 500; i += 50) { CGSize constrainedSize = CGSizeMake(i, i); - CGSize calculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; + CGSize calculatedSize = [_editableTextNode measure:constrainedSize]; XCTAssertTrue(calculatedSize.width <= constrainedSize.width, @"Calculated width (%f) should be less than or equal to constrained width (%f)", calculatedSize.width, constrainedSize.width); XCTAssertTrue(calculatedSize.height <= constrainedSize.height, @"Calculated height (%f) should be less than or equal to constrained height (%f)", calculatedSize.height, constrainedSize.height); } @@ -153,8 +164,8 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) { for (NSInteger i = 10; i < 500; i += 50) { CGSize constrainedSize = CGSizeMake(i, i); - CGSize calculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; - CGSize recalculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; + CGSize calculatedSize = [_editableTextNode measure:constrainedSize]; + CGSize recalculatedSize = [_editableTextNode measure:calculatedSize]; XCTAssertTrue(CGSizeEqualToSizeWithIn(calculatedSize, recalculatedSize, 4.0), @"Recalculated size %@ should be same as original size %@", NSStringFromCGSize(recalculatedSize), NSStringFromCGSize(calculatedSize)); } @@ -164,8 +175,8 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) { for (CGFloat i = 10; i < 500; i *= 1.3) { CGSize constrainedSize = CGSizeMake(i, i); - CGSize calculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; - CGSize recalculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; + CGSize calculatedSize = [_editableTextNode measure:constrainedSize]; + CGSize recalculatedSize = [_editableTextNode measure:calculatedSize]; XCTAssertTrue(CGSizeEqualToSizeWithIn(calculatedSize, recalculatedSize, 11.0), @"Recalculated size %@ should be same as original size %@", NSStringFromCGSize(recalculatedSize), NSStringFromCGSize(calculatedSize)); } diff --git a/AsyncDisplayKitTests/ASImageNodeSnapshotTests.m b/AsyncDisplayKitTests/ASImageNodeSnapshotTests.m index 8788052f..a6e6b857 100644 --- a/AsyncDisplayKitTests/ASImageNodeSnapshotTests.m +++ b/AsyncDisplayKitTests/ASImageNodeSnapshotTests.m @@ -20,8 +20,7 @@ - (UIImage *)testImage { NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"logo-square" - ofType:@"png" - inDirectory:@"TestResources"]; + ofType:@"png" inDirectory:@"TestResources"]; return [UIImage imageWithContentsOfFile:path]; } @@ -30,32 +29,30 @@ // trivial test case to ensure ASSnapshotTestCase works ASImageNode *imageNode = [[ASImageNode alloc] init]; imageNode.image = [self testImage]; - [imageNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))]; + [imageNode measure:CGSizeMake(100, 100)]; ASSnapshotVerifyNode(imageNode, nil); } - (void)testForcedScaling { - CGSize forcedImageSize = CGSizeMake(100, 100); - ASImageNode *imageNode = [[ASImageNode alloc] init]; - imageNode.forcedSize = forcedImageSize; + imageNode.image = [self testImage]; + imageNode.forcedSize = CGSizeMake(100, 100); // Snapshot testing requires that node is formally laid out. - [imageNode setSizeWithCGSize:forcedImageSize]; - [imageNode layoutThatFits:ASSizeRangeMake(CGSizeZero, forcedImageSize)]; + imageNode.preferredFrameSize = CGSizeMake(100, 100); + [imageNode measure:CGSizeMake(100, 100)]; + ASSnapshotVerifyNode(imageNode, @"first"); - [imageNode setSizeWithCGSize:CGSizeMake(200, 200)]; - [imageNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(200, 200))]; + imageNode.preferredFrameSize = CGSizeMake(200, 200); + [imageNode measure:CGSizeMake(200, 200)]; ASSnapshotVerifyNode(imageNode, @"second"); - XCTAssert(CGImageGetWidth((CGImageRef)imageNode.contents) == forcedImageSize.width * imageNode.contentsScale && - CGImageGetHeight((CGImageRef)imageNode.contents) == forcedImageSize.height * imageNode.contentsScale, - @"Contents should be 100 x 100 by contents scale."); + XCTAssert(CGImageGetWidth((CGImageRef)imageNode.contents) == 100 * imageNode.contentsScale && CGImageGetHeight((CGImageRef)imageNode.contents) == 100 * imageNode.contentsScale, @"contents should be 100 x 100 by contents scale."); } @end diff --git a/AsyncDisplayKitTests/ASInsetLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASInsetLayoutSpecSnapshotTests.mm index f286fa89..867aa76c 100644 --- a/AsyncDisplayKitTests/ASInsetLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASInsetLayoutSpecSnapshotTests.mm @@ -50,14 +50,12 @@ static NSString *nameForInsets(UIEdgeInsets insets) for (NSUInteger combination = 0; combination < 16; combination++) { UIEdgeInsets insets = insetsForCombination(combination, 10); ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor grayColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], {10, 10}); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); + foregroundNode.staticSize = {10, 10}; ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec - backgroundLayoutSpecWithChild: - [ASInsetLayoutSpec - insetLayoutSpecWithInsets:insets - child:foregroundNode] + backgroundLayoutSpecWithChild:[ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:foregroundNode] background:backgroundNode]; static ASSizeRange kVariableSize = {{0, 0}, {300, 300}}; @@ -73,14 +71,12 @@ static NSString *nameForInsets(UIEdgeInsets insets) for (NSUInteger combination = 0; combination < 16; combination++) { UIEdgeInsets insets = insetsForCombination(combination, 10); ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor grayColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], {10, 10}); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); + foregroundNode.staticSize = {10, 10}; ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec - backgroundLayoutSpecWithChild: - [ASInsetLayoutSpec - insetLayoutSpecWithInsets:insets - child:foregroundNode] + backgroundLayoutSpecWithChild:[ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:foregroundNode] background:backgroundNode]; static ASSizeRange kFixedSize = {{300, 300}, {300, 300}}; @@ -97,14 +93,12 @@ static NSString *nameForInsets(UIEdgeInsets insets) for (NSUInteger combination = 0; combination < 16; combination++) { UIEdgeInsets insets = insetsForCombination(combination, 0); ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor grayColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], {10, 10}); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); + foregroundNode.staticSize = {10, 10}; ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec - backgroundLayoutSpecWithChild: - [ASInsetLayoutSpec - insetLayoutSpecWithInsets:insets - child:foregroundNode] + backgroundLayoutSpecWithChild:[ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:foregroundNode] background:backgroundNode]; static ASSizeRange kFixedSize = {{300, 300}, {300, 300}}; diff --git a/AsyncDisplayKitTests/ASLayoutSpecSnapshotTestsHelper.h b/AsyncDisplayKitTests/ASLayoutSpecSnapshotTestsHelper.h index c632b507..fc64d117 100644 --- a/AsyncDisplayKitTests/ASLayoutSpecSnapshotTestsHelper.h +++ b/AsyncDisplayKitTests/ASLayoutSpecSnapshotTestsHelper.h @@ -31,16 +31,17 @@ identifier:(NSString *)identifier; @end -__attribute__((overloadable)) static inline ASDisplayNode *ASDisplayNodeWithBackgroundColor(UIColor *backgroundColor, CGSize size) { - ASDisplayNode *node = [[ASDisplayNode alloc] init]; +@interface ASStaticSizeDisplayNode : ASDisplayNode + +@property (nonatomic) CGSize staticSize; + +@end + +static inline ASStaticSizeDisplayNode *ASDisplayNodeWithBackgroundColor(UIColor *backgroundColor) +{ + ASStaticSizeDisplayNode *node = [[ASStaticSizeDisplayNode alloc] init]; node.layerBacked = YES; node.backgroundColor = backgroundColor; - node.width = ASDimensionMakeWithPoints(size.width); - node.height = ASDimensionMakeWithPoints(size.height); + node.staticSize = CGSizeZero; return node; } - -__attribute__((overloadable)) static inline ASDisplayNode *ASDisplayNodeWithBackgroundColor(UIColor *backgroundColor) -{ - return ASDisplayNodeWithBackgroundColor(backgroundColor, CGSizeZero); -} diff --git a/AsyncDisplayKitTests/ASLayoutSpecSnapshotTestsHelper.m b/AsyncDisplayKitTests/ASLayoutSpecSnapshotTestsHelper.m index e2d908d0..fe173586 100644 --- a/AsyncDisplayKitTests/ASLayoutSpecSnapshotTestsHelper.m +++ b/AsyncDisplayKitTests/ASLayoutSpecSnapshotTestsHelper.m @@ -39,7 +39,7 @@ node.layoutSpecUnderTest = layoutSpec; - [node layoutThatFits:sizeRange]; + [node measureWithSizeRange:sizeRange]; ASSnapshotVerifyNode(node, identifier); } @@ -60,3 +60,12 @@ } @end + +@implementation ASStaticSizeDisplayNode + +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize +{ + return _staticSize; +} + +@end diff --git a/AsyncDisplayKitTests/ASOverlayLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASOverlayLayoutSpecSnapshotTests.mm index 3e654a94..04856059 100644 --- a/AsyncDisplayKitTests/ASOverlayLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASOverlayLayoutSpecSnapshotTests.mm @@ -23,7 +23,8 @@ static const ASSizeRange kSize = {{320, 320}, {320, 320}}; - (void)testOverlay { ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor blackColor], {20, 20}); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor blackColor]); + foregroundNode.staticSize = {20, 20}; ASLayoutSpec *layoutSpec = [ASOverlayLayoutSpec diff --git a/AsyncDisplayKitTests/ASRatioLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASRatioLayoutSpecSnapshotTests.mm index ccede39d..9cc878b6 100644 --- a/AsyncDisplayKitTests/ASRatioLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASRatioLayoutSpecSnapshotTests.mm @@ -21,7 +21,8 @@ static const ASSizeRange kFixedSize = {{0, 0}, {100, 100}}; - (void)testRatioLayoutSpecWithRatio:(CGFloat)ratio childSize:(CGSize)childSize identifier:(NSString *)identifier { - ASDisplayNode *subnode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], childSize); + ASStaticSizeDisplayNode *subnode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); + subnode.staticSize = childSize; ASLayoutSpec *layoutSpec = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:ratio child:subnode]; diff --git a/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm index 4b903dff..fdbf3713 100644 --- a/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm @@ -23,6 +23,7 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}}; - (void)testWithOptions { + [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionStart]; [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionCenter]; [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionEnd]; @@ -56,16 +57,14 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}}; sizingOptions:(ASRelativeLayoutSpecSizingOption)sizingOptions { ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], CGSizeMake(70, 100)); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); + foregroundNode.staticSize = {70, 100}; ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild: [ASRelativeLayoutSpec - relativePositionLayoutSpecWithHorizontalPosition:horizontalPosition - verticalPosition:verticalPosition - sizingOption:sizingOptions - child:foregroundNode] + relativePositionLayoutSpecWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOptions child:foregroundNode] background:backgroundNode]; [self testLayoutSpec:layoutSpec @@ -106,26 +105,17 @@ static NSString *suffixForPositionOptions(ASRelativeLayoutSpecPosition horizonta - (void)testMinimumSizeRangeIsGivenToChildWhenNotPositioning { ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); - ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor], CGSizeMake(10, 10)); + 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]; + 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]; + ASRelativeLayoutSpec *layoutSpec = [ASRelativeLayoutSpec + relativePositionLayoutSpecWithHorizontalPosition:ASRelativeLayoutSpecPositionStart verticalPosition:ASRelativeLayoutSpecPositionStart sizingOption:{} child:childSpec]; + [self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier:nil]; } diff --git a/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm index 32e5a53d..3b30272d 100644 --- a/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm @@ -23,31 +23,26 @@ #pragma mark - Utility methods -static NSArray *defaultSubnodes() +static NSArray *defaultSubnodes() { return defaultSubnodesWithSameSize(CGSizeZero, NO); } -static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) +static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) { - NSArray *subnodes = @[ - ASDisplayNodeWithBackgroundColor([UIColor redColor], subnodeSize), - ASDisplayNodeWithBackgroundColor([UIColor blueColor], subnodeSize), - ASDisplayNodeWithBackgroundColor([UIColor greenColor], subnodeSize) - ]; - for (ASDisplayNode *subnode in subnodes) { + NSArray *subnodes = @[ + ASDisplayNodeWithBackgroundColor([UIColor redColor]), + ASDisplayNodeWithBackgroundColor([UIColor blueColor]), + ASDisplayNodeWithBackgroundColor([UIColor greenColor]) + ]; + for (ASStaticSizeDisplayNode *subnode in subnodes) { + subnode.staticSize = subnodeSize; subnode.flexGrow = flex; subnode.flexShrink = flex; } return subnodes; } -static void setCGSizeToNode(CGSize size, ASDisplayNode *node) -{ - node.width = ASDimensionMakeWithPoints(size.width); - node.height = ASDimensionMakeWithPoints(size.height); -} - - (void)testStackLayoutSpecWithJustify:(ASStackLayoutJustifyContent)justify flex:(BOOL)flex sizeRange:(ASSizeRange)sizeRange @@ -58,7 +53,7 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .justifyContent = justify }; - NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, flex); + NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, flex); [self testStackLayoutSpecWithStyle:style sizeRange:sizeRange subnodes:subnodes identifier:identifier]; } @@ -68,13 +63,13 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) itemsVerticalAlignment:(ASVerticalAlignment)verticalAlignment identifier:(NSString *)identifier { - NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); + NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); ASStackLayoutSpec *stackLayoutSpec = [[ASStackLayoutSpec alloc] init]; stackLayoutSpec.direction = direction; stackLayoutSpec.children = subnodes; - stackLayoutSpec.horizontalAlignment = horizontalAlignment; - stackLayoutSpec.verticalAlignment = verticalAlignment; + [stackLayoutSpec setHorizontalAlignment:horizontalAlignment]; + [stackLayoutSpec setVerticalAlignment:verticalAlignment]; CGSize exactSize = CGSizeMake(200, 200); static ASSizeRange kSize = ASSizeRangeMake(exactSize, exactSize); @@ -95,14 +90,11 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) subnodes:(NSArray *)subnodes identifier:(NSString *)identifier { - ASStackLayoutSpec *stackLayoutSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:style.direction - spacing:style.spacing - justifyContent:style.justifyContent - alignItems:style.alignItems - children:children]; - + ASStackLayoutSpec *stackLayoutSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:style.direction + spacing:style.spacing + justifyContent:style.justifyContent + alignItems:style.alignItems + children:children]; [self testStackLayoutSpec:stackLayoutSpec sizeRange:sizeRange subnodes:subnodes identifier:identifier]; } @@ -112,6 +104,7 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) identifier:(NSString *)identifier { ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor whiteColor]); + ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:stackLayoutSpec background:backgroundNode]; NSMutableArray *newSubnodes = [NSMutableArray arrayWithObject:backgroundNode]; @@ -152,8 +145,8 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; - NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); - subnodes[1].flexShrink = YES; + NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); + ((ASDisplayNode *)subnodes[1]).flexShrink = YES; // Width is 75px--that's less than the sum of the widths of the children, which is 100px. static ASSizeRange kSize = {{75, 0}, {75, 150}}; @@ -164,8 +157,8 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; - NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, YES); - setCGSizeToNode({150, 150}, subnodes[1]); + NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, YES); + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {150, 150}; // width 300px; height 0-150px. static ASSizeRange kUnderflowSize = {{300, 0}, {300, 150}}; @@ -180,10 +173,10 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical}; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 50}, subnodes[1]); - setCGSizeToNode({150, 50}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 50}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 50}; // width 0-300px; height 300px static ASSizeRange kVariableHeight = {{0, 300}, {300, 300}}; @@ -201,10 +194,10 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .spacing = 10 }; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 50}, subnodes[1]); - setCGSizeToNode({150, 50}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 50}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 50}; // width 0-300px; height 300px static ASSizeRange kVariableHeight = {{0, 300}, {300, 300}}; @@ -219,16 +212,12 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) ASLayoutSpec *layoutSpec = [ASInsetLayoutSpec - insetLayoutSpecWithInsets:{10, 10, 10, 10} + insetLayoutSpecWithInsets:{10, 10, 10 ,10} child: [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild: [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical - spacing:10 - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStretch - children:@[]] + stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:10 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStretch children:@[]] background:backgroundNode]]; // width 300px; height 0-300px @@ -242,28 +231,28 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) static ASSizeRange kAnySize = {{0, 0}, {INFINITY, INFINITY}}; ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical}; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 70}, subnodes[1]); - setCGSizeToNode({150, 90}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - subnodes[1].spacingBefore = 10; - subnodes[2].spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 10; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 20; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingBefore"]; // Reset above spacing values - subnodes[1].spacingBefore = 0; - subnodes[2].spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 0; - subnodes[1].spacingAfter = 10; - subnodes[2].spacingAfter = 20; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingAfter = 10; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingAfter = 20; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingAfter"]; // Reset above spacing values - subnodes[1].spacingAfter = 0; - subnodes[2].spacingAfter = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingAfter = 0; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingAfter = 0; style.spacing = 10; - subnodes[1].spacingBefore = -10; - subnodes[1].spacingAfter = -10; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = -10; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingAfter = -10; [self testStackLayoutSpecWithStyle:style sizeRange:kAnySize subnodes:subnodes identifier:@"spacingBalancedOut"]; } @@ -274,14 +263,14 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .justifyContent = ASStackLayoutJustifyContentCenter }; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 70}, subnodes[1]); - setCGSizeToNode({150, 90}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - subnodes[0].spacingBefore = 0; - subnodes[1].spacingBefore = 20; - subnodes[2].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30; // width 0-300px; height 300px static ASSizeRange kVariableHeight = {{0, 300}, {300, 300}}; @@ -295,7 +284,8 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .justifyContent = ASStackLayoutJustifyContentSpaceBetween }; - ASDisplayNode *child = ASDisplayNodeWithBackgroundColor([UIColor redColor], {50, 50}); + ASStaticSizeDisplayNode *child = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + child.staticSize = {50, 50}; // width 300px; height 0-INF static ASSizeRange kVariableHeight = {{300, 0}, {300, INFINITY}}; @@ -309,7 +299,8 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .justifyContent = ASStackLayoutJustifyContentSpaceAround }; - ASDisplayNode *child = ASDisplayNodeWithBackgroundColor([UIColor redColor], {50, 50}); + ASStaticSizeDisplayNode *child = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + child.staticSize = {50, 50}; // width 300px; height 0-INF static ASSizeRange kVariableHeight = {{300, 0}, {300, INFINITY}}; @@ -334,11 +325,12 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; - ASDisplayNode * subnode1 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); - ASDisplayNode * subnode2 = ASDisplayNodeWithBackgroundColor([UIColor redColor], {50, 50}); + ASStaticSizeDisplayNode * subnode1 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); + ASStaticSizeDisplayNode * subnode2 = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + subnode2.staticSize = {50, 50}; ASRatioLayoutSpec *child1 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.5 child:subnode1]; - child1.flexBasis = ASDimensionMakeWithFraction(1); + child1.flexBasis = ASRelativeDimensionMakeWithFraction(1); child1.flexGrow = YES; child1.flexShrink = YES; @@ -353,13 +345,15 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .alignItems = ASStackLayoutAlignItemsCenter }; - ASDisplayNode *subnode1 = ASDisplayNodeWithBackgroundColor([UIColor redColor], {100, 100}); + ASStaticSizeDisplayNode *subnode1 = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + subnode1.staticSize = {100, 100}; subnode1.flexShrink = YES; - ASDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor], {50, 50}); + ASStaticSizeDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); + subnode2.staticSize = {50, 50}; subnode2.flexShrink = YES; - NSArray *subnodes = @[subnode1, subnode2]; + NSArray *subnodes = @[subnode1, subnode2]; static ASSizeRange kFixedWidth = {{150, 0}, {150, 100}}; [self testStackLayoutSpecWithStyle:style sizeRange:kFixedWidth subnodes:subnodes identifier:nil]; } @@ -368,12 +362,14 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; - ASDisplayNode *subnode1 = ASDisplayNodeWithBackgroundColor([UIColor redColor], {100, 100}); + ASStaticSizeDisplayNode *subnode1 = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + subnode1.staticSize = {100, 100}; - ASDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor], {50, 50}); + ASStaticSizeDisplayNode *subnode2 = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); + subnode2.staticSize = {50, 50}; subnode2.alignSelf = ASStackLayoutAlignSelfCenter; - NSArray *subnodes = @[subnode1, subnode2]; + NSArray *subnodes = @[subnode1, subnode2]; static ASSizeRange kFixedWidth = {{150, 0}, {150, INFINITY}}; [self testStackLayoutSpecWithStyle:style sizeRange:kFixedWidth subnodes:subnodes identifier:nil]; } @@ -386,14 +382,14 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .alignItems = ASStackLayoutAlignItemsStart }; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 70}, subnodes[1]); - setCGSizeToNode({150, 90}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - subnodes[0].spacingBefore = 0; - subnodes[1].spacingBefore = 20; - subnodes[2].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30; static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; @@ -407,14 +403,14 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .alignItems = ASStackLayoutAlignItemsEnd }; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 70}, subnodes[1]); - setCGSizeToNode({150, 90}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - subnodes[0].spacingBefore = 0; - subnodes[1].spacingBefore = 20; - subnodes[2].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30; static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; @@ -428,14 +424,14 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .alignItems = ASStackLayoutAlignItemsCenter }; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 70}, subnodes[1]); - setCGSizeToNode({150, 90}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - subnodes[0].spacingBefore = 0; - subnodes[1].spacingBefore = 20; - subnodes[2].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30; static ASSizeRange kExactSize = {{300, 300}, {300, 300}}; [self testStackLayoutSpecWithStyle:style sizeRange:kExactSize subnodes:subnodes identifier:nil]; @@ -449,14 +445,14 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .alignItems = ASStackLayoutAlignItemsStretch }; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 70}, subnodes[1]); - setCGSizeToNode({150, 90}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - subnodes[0].spacingBefore = 0; - subnodes[1].spacingBefore = 20; - subnodes[2].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30; static ASSizeRange kVariableSize = {{200, 200}, {300, 300}}; // all children should be 200px wide @@ -471,14 +467,14 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) .alignItems = ASStackLayoutAlignItemsStretch }; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({100, 70}, subnodes[1]); - setCGSizeToNode({150, 90}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 70}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {150, 90}; - subnodes[0].spacingBefore = 0; - subnodes[1].spacingBefore = 20; - subnodes[2].spacingBefore = 30; + ((ASStaticSizeDisplayNode *)subnodes[0]).spacingBefore = 0; + ((ASStaticSizeDisplayNode *)subnodes[1]).spacingBefore = 20; + ((ASStaticSizeDisplayNode *)subnodes[2]).spacingBefore = 30; static ASSizeRange kVariableSize = {{50, 50}, {300, 300}}; // all children should be 150px wide @@ -495,12 +491,12 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; - NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); - setCGSizeToNode({150, 150}, subnodes[1]); + NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {150, 150}; - for (ASDisplayNode *subnode in subnodes) { + for (ASStaticSizeDisplayNode *subnode in subnodes) { subnode.flexGrow = YES; - subnode.flexBasis = ASDimensionMakeWithPoints(10); + subnode.flexBasis = ASRelativeDimensionMakeWithPoints(10); } // width 300px; height 0-150px. @@ -516,14 +512,15 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; - NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); - for (ASDisplayNode *subnode in subnodes) { + NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO); + + for (ASStaticSizeDisplayNode *subnode in subnodes) { subnode.flexGrow = YES; } // This should override the intrinsic size of 50pts and instead compute to 50% = 100pts. // The result should be that the red box is twice as wide as the blue and gree boxes after flexing. - subnodes[0].flexBasis = ASDimensionMakeWithFraction(0.5); + ((ASStaticSizeDisplayNode *)subnodes[0]).flexBasis = ASRelativeDimensionMakeWithFraction(0.5); static ASSizeRange kSize = {{200, 0}, {200, INFINITY}}; [self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil]; @@ -533,13 +530,13 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({50, 50}, subnodes[0]); - setCGSizeToNode({150, 150}, subnodes[1]); - setCGSizeToNode({150, 50}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {50, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {150, 150}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {50, 50}; - for (ASDisplayNode *subnode in subnodes) { - subnode.flexBasis = ASDimensionMakeWithPoints(20); + for (ASStaticSizeDisplayNode *subnode in subnodes) { + subnode.flexBasis = ASRelativeDimensionMakeWithPoints(20); } static ASSizeRange kSize = {{300, 0}, {300, 150}}; @@ -548,11 +545,13 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) - (void)testCrossAxisStretchingOccursAfterStackAxisFlexing { - NSArray *subnodes = @[ - ASDisplayNodeWithBackgroundColor([UIColor greenColor]), - ASDisplayNodeWithBackgroundColor([UIColor blueColor], {10, 0}), - ASDisplayNodeWithBackgroundColor([UIColor redColor], {3000, 3000}) - ]; + NSArray *subnodes = @[ + ASDisplayNodeWithBackgroundColor([UIColor greenColor]), + ASDisplayNodeWithBackgroundColor([UIColor blueColor]), + ASDisplayNodeWithBackgroundColor([UIColor redColor]) + ]; + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {10, 0}; + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {3000, 3000}; ASRatioLayoutSpec *child2 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.0 child:subnodes[2]]; child2.flexGrow = YES; @@ -566,12 +565,7 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(10, 10, 10, 10) child: - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:0 - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStretch - children:@[subnodes[1], child2]] + [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStretch children:@[subnodes[1], child2,]] ] background:subnodes[0]]; @@ -582,16 +576,17 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node) - (void)testViolationIsDistributedEquallyAmongFlexibleChildren { ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal}; - - NSArray *subnodes = defaultSubnodes(); - setCGSizeToNode({300, 50}, subnodes[0]); - setCGSizeToNode({100, 50}, subnodes[1]); - setCGSizeToNode({200, 50}, subnodes[2]); + NSArray *subnodes = defaultSubnodes(); - subnodes[0].flexShrink = YES; - subnodes[1].flexShrink = NO; - subnodes[2].flexShrink = YES; + ((ASStaticSizeDisplayNode *)subnodes[0]).staticSize = {300, 50}; + ((ASStaticSizeDisplayNode *)subnodes[0]).flexShrink = YES; + + ((ASStaticSizeDisplayNode *)subnodes[1]).staticSize = {100, 50}; + ((ASStaticSizeDisplayNode *)subnodes[1]).flexShrink = NO; + + ((ASStaticSizeDisplayNode *)subnodes[2]).staticSize = {200, 50}; + ((ASStaticSizeDisplayNode *)subnodes[2]).flexShrink = YES; // A width of 400px results in a violation of 200px. This is distributed equally among each flexible child, // causing both of them to be shrunk by 100px, resulting in widths of 300px, 100px, and 50px. diff --git a/AsyncDisplayKitTests/ASStaticLayoutSpecSnapshotTests.m b/AsyncDisplayKitTests/ASStaticLayoutSpecSnapshotTests.m index 103ea755..b747dbb0 100644 --- a/AsyncDisplayKitTests/ASStaticLayoutSpecSnapshotTests.m +++ b/AsyncDisplayKitTests/ASStaticLayoutSpecSnapshotTests.m @@ -22,34 +22,46 @@ - (void)testSizingBehaviour { - [self testWithSizeRange:ASSizeRangeMake(CGSizeMake(150, 200), CGSizeMake(INFINITY, INFINITY)) + [self testWithSizeRange:ASSizeRangeMake(CGSizeMake(150, 200), CGSizeMake(FLT_MAX, FLT_MAX)) identifier:@"underflowChildren"]; [self testWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(50, 100)) identifier:@"overflowChildren"]; // Expect the spec to wrap its content because children sizes are between constrained size - [self testWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY / 2, INFINITY / 2)) + [self testWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(FLT_MAX / 2, FLT_MAX / 2)) identifier:@"wrappedChildren"]; } - (void)testChildrenMeasuredWithAutoMaxSize { - ASDisplayNode *firstChild = ASDisplayNodeWithBackgroundColor([UIColor redColor], (CGSize){50, 50}); + ASStaticSizeDisplayNode *firstChild = ASDisplayNodeWithBackgroundColor([UIColor redColor]); firstChild.layoutPosition = CGPointMake(0, 0); + firstChild.staticSize = CGSizeMake(50, 50); - ASDisplayNode *secondChild = ASDisplayNodeWithBackgroundColor([UIColor blueColor], (CGSize){100, 100}); + ASStaticSizeDisplayNode *secondChild = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); secondChild.layoutPosition = CGPointMake(10, 60); + secondChild.staticSize = CGSizeMake(100, 100); ASSizeRange sizeRange = ASSizeRangeMake(CGSizeMake(10, 10), CGSizeMake(110, 160)); [self testWithChildren:@[firstChild, secondChild] sizeRange:sizeRange identifier:nil]; + + XCTAssertTrue(ASSizeRangeEqualToSizeRange(firstChild.constrainedSizeForCalculatedLayout, + ASSizeRangeMake(CGSizeZero, sizeRange.max))); + CGSize secondChildMaxSize = CGSizeMake(sizeRange.max.width - secondChild.layoutPosition.x, + sizeRange.max.height - secondChild.layoutPosition.y); + XCTAssertTrue(ASSizeRangeEqualToSizeRange(secondChild.constrainedSizeForCalculatedLayout, + ASSizeRangeMake(CGSizeZero, secondChildMaxSize))); } - (void)testWithSizeRange:(ASSizeRange)sizeRange identifier:(NSString *)identifier { - ASDisplayNode *firstChild = ASDisplayNodeWithBackgroundColor([UIColor redColor], (CGSize){50, 50}); + ASDisplayNode *firstChild = ASDisplayNodeWithBackgroundColor([UIColor redColor]); firstChild.layoutPosition = CGPointMake(0, 0); + firstChild.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(CGSizeMake(50, 50)); - ASDisplayNode *secondChild = ASDisplayNodeWithBackgroundColor([UIColor blueColor], (CGSize){100, 100}); + + ASDisplayNode *secondChild = ASDisplayNodeWithBackgroundColor([UIColor blueColor]); secondChild.layoutPosition = CGPointMake(0, 50); + secondChild.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(CGSizeMake(100, 100)); [self testWithChildren:@[firstChild, secondChild] sizeRange:sizeRange identifier:identifier]; } @@ -61,12 +73,9 @@ NSMutableArray *subnodes = [NSMutableArray arrayWithArray:children]; [subnodes insertObject:backgroundNode atIndex:0]; - ASLayoutSpec *layoutSpec = - [ASBackgroundLayoutSpec - backgroundLayoutSpecWithChild: - [ASStaticLayoutSpec - staticLayoutSpecWithChildren:children] - background:backgroundNode]; + ASStaticLayoutSpec *staticLayoutSpec = [ASStaticLayoutSpec staticLayoutSpecWithChildren:children]; + ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:staticLayoutSpec + background:backgroundNode]; [self testLayoutSpec:layoutSpec sizeRange:sizeRange subnodes:subnodes identifier:identifier]; } diff --git a/AsyncDisplayKitTests/ASTableViewTests.m b/AsyncDisplayKitTests/ASTableViewTests.m index 329be7e4..2c282de1 100644 --- a/AsyncDisplayKitTests/ASTableViewTests.m +++ b/AsyncDisplayKitTests/ASTableViewTests.m @@ -148,7 +148,7 @@ - (ASSizeRange)tableView:(ASTableView *)tableView constrainedSizeForRowAtIndexPath:(NSIndexPath *)indexPath { - return ASSizeRangeMake(CGSizeMake(10, 42)); + return ASSizeRangeMakeExactSize(CGSizeMake(10, 42)); } @end diff --git a/AsyncDisplayKitTests/ASTextNodePerformanceTests.m b/AsyncDisplayKitTests/ASTextNodePerformanceTests.m index f585d501..6f0f1c17 100644 --- a/AsyncDisplayKitTests/ASTextNodePerformanceTests.m +++ b/AsyncDisplayKitTests/ASTextNodePerformanceTests.m @@ -9,7 +9,6 @@ #import #import "ASPerformanceTestContext.h" #import -#import #import "ASinternalHelpers.h" #import "ASXCTExtensions.h" #include "CGRect+ASConvenience.h" @@ -72,7 +71,7 @@ static NSString *const kTestCaseUIKitWithReusedContext = @"UIKitReusedContext"; NSAttributedString *text = data[i % data.count]; startMeasuring(); node.attributedText = text; - asdkSize = [node layoutThatFits:ASSizeRangeMake(CGSizeZero, maxSize)].size; + asdkSize = [node measure:maxSize]; stopMeasuring(); }]; ctx.results[kTestCaseASDK].userInfo[@"size"] = NSStringFromCGSize(asdkSize); @@ -102,7 +101,7 @@ static NSString *const kTestCaseUIKitWithReusedContext = @"UIKitReusedContext"; ASTextNode *node = [[ASTextNode alloc] init]; startMeasuring(); node.attributedText = text; - asdkSize = [node layoutThatFits:ASSizeRangeMake(CGSizeZero, maxSize)].size; + asdkSize = [node measure:maxSize]; stopMeasuring(); }]; ctx.results[kTestCaseASDK].userInfo[@"size"] = NSStringFromCGSize(asdkSize); @@ -132,7 +131,7 @@ static NSString *const kTestCaseUIKitWithReusedContext = @"UIKitReusedContext"; ASTextNode *node = [[ASTextNode alloc] init]; startMeasuring(); node.attributedText = text; - asdkSize = [node layoutThatFits:ASSizeRangeMake(CGSizeZero, maxSize)].size; + asdkSize = [node measure:maxSize]; stopMeasuring(); }]; testCtx.results[kTestCaseASDK].userInfo[@"size"] = NSStringFromCGSize(asdkSize); diff --git a/AsyncDisplayKitTests/ASTextNodeSnapshotTests.m b/AsyncDisplayKitTests/ASTextNodeSnapshotTests.m index 00e6b957..b2c64caf 100644 --- a/AsyncDisplayKitTests/ASTextNodeSnapshotTests.m +++ b/AsyncDisplayKitTests/ASTextNodeSnapshotTests.m @@ -10,8 +10,8 @@ // #import "ASSnapshotTestCase.h" + #import -#import "ASLayout.h" @interface ASTextNodeSnapshotTests : ASSnapshotTestCase @@ -25,7 +25,7 @@ ASTextNode *textNode = [[ASTextNode alloc] init]; textNode.attributedText = [[NSAttributedString alloc] initWithString:@"judar" attributes:@{NSFontAttributeName : [UIFont italicSystemFontOfSize:24]}]; - [textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX))]; + [textNode measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX))]; textNode.textContainerInset = UIEdgeInsetsMake(0, 2, 0, 2); ASSnapshotVerifyNode(textNode, nil); @@ -40,7 +40,7 @@ textNode.attributedText = [[NSAttributedString alloc] initWithString:@"judar judar judar judar judar judar" attributes:@{ NSFontAttributeName : [UIFont systemFontOfSize:30] }]; - [textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 80))]; + [textNode measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 80))]; textNode.frame = CGRectMake(50, 50, textNode.calculatedSize.width, textNode.calculatedSize.height); textNode.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10); @@ -62,7 +62,7 @@ textNode.attributedText = [[NSAttributedString alloc] initWithString:@"yolo" attributes:@{ NSFontAttributeName : [UIFont systemFontOfSize:30] }]; - [textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX))]; + [textNode measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX))]; textNode.frame = CGRectMake(50, 50, textNode.calculatedSize.width, textNode.calculatedSize.height); textNode.textContainerInset = UIEdgeInsetsMake(5, 10, 10, 5); diff --git a/AsyncDisplayKitTests/ASTextNodeTests.m b/AsyncDisplayKitTests/ASTextNodeTests.m index 2448f074..cb96f4fc 100644 --- a/AsyncDisplayKitTests/ASTextNodeTests.m +++ b/AsyncDisplayKitTests/ASTextNodeTests.m @@ -12,7 +12,6 @@ #import -#import #import #import @@ -112,7 +111,7 @@ { for (NSInteger i = 10; i < 500; i += 50) { CGSize constrainedSize = CGSizeMake(i, i); - CGSize calculatedSize = [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; + CGSize calculatedSize = [_textNode measure:constrainedSize]; XCTAssertTrue(calculatedSize.width <= constrainedSize.width, @"Calculated width (%f) should be less than or equal to constrained width (%f)", calculatedSize.width, constrainedSize.width); XCTAssertTrue(calculatedSize.height <= constrainedSize.height, @"Calculated height (%f) should be less than or equal to constrained height (%f)", calculatedSize.height, constrainedSize.height); } @@ -122,8 +121,8 @@ { for (NSInteger i = 10; i < 500; i += 50) { CGSize constrainedSize = CGSizeMake(i, i); - CGSize calculatedSize = [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; - CGSize recalculatedSize = [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; + CGSize calculatedSize = [_textNode measure:constrainedSize]; + CGSize recalculatedSize = [_textNode measure:constrainedSize]; XCTAssertTrue(CGSizeEqualToSizeWithIn(calculatedSize, recalculatedSize, 4.0), @"Recalculated size %@ should be same as original size %@", NSStringFromCGSize(recalculatedSize), NSStringFromCGSize(calculatedSize)); } @@ -133,8 +132,8 @@ { for (CGFloat i = 10; i < 500; i *= 1.3) { CGSize constrainedSize = CGSizeMake(i, i); - CGSize calculatedSize = [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; - CGSize recalculatedSize = [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; + CGSize calculatedSize = [_textNode measure:constrainedSize]; + CGSize recalculatedSize = [_textNode measure:constrainedSize]; XCTAssertTrue(CGSizeEqualToSizeWithIn(calculatedSize, recalculatedSize, 11.0), @"Recalculated size %@ should be same as original size %@", NSStringFromCGSize(recalculatedSize), NSStringFromCGSize(calculatedSize)); } @@ -144,9 +143,9 @@ { _textNode.placeholderEnabled = YES; - XCTAssertNoThrow([_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeZero)], @"Measure with zero size and placeholder enabled should not throw an exception"); - XCTAssertNoThrow([_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(0, 100))], @"Measure with zero width and placeholder enabled should not throw an exception"); - XCTAssertNoThrow([_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 0))], @"Measure with zero height and placeholder enabled should not throw an exception"); + XCTAssertNoThrow([_textNode measure:CGSizeZero], @"Measure with zero size and placeholder enabled should not throw an exception"); + XCTAssertNoThrow([_textNode measure:CGSizeMake(0, 100)], @"Measure with zero width and placeholder enabled should not throw an exception"); + XCTAssertNoThrow([_textNode measure:CGSizeMake(100, 0)], @"Measure with zero height and placeholder enabled should not throw an exception"); } - (void)testAccessibility @@ -171,7 +170,7 @@ ASTextNodeTestDelegate *delegate = [ASTextNodeTestDelegate new]; _textNode.delegate = delegate; - [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))]; + [_textNode measure:CGSizeMake(100, 100)]; NSRange returnedLinkRange; NSString *returnedAttributeName; NSString *returnedLinkAttributeValue = [_textNode linkAttributeValueAtPoint:CGPointMake(3, 3) attributeName:&returnedAttributeName range:&returnedLinkRange]; @@ -193,7 +192,7 @@ ASTextNodeTestDelegate *delegate = [ASTextNodeTestDelegate new]; _textNode.delegate = delegate; - CGSize calculatedSize = [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))].size; + CGSize calculatedSize = [_textNode measure:CGSizeMake(100, 100)]; NSRange returnedLinkRange = NSMakeRange(NSNotFound, 0); NSRange expectedRange = NSMakeRange(NSNotFound, 0); NSString *returnedAttributeName; @@ -219,9 +218,9 @@ - (void)testAddingExclusionPathsShouldInvalidateAndIncreaseTheSize { CGSize constrainedSize = CGSizeMake(100, CGFLOAT_MAX); - CGSize sizeWithoutExclusionPaths = [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; + CGSize sizeWithoutExclusionPaths = [_textNode measure:constrainedSize]; _textNode.exclusionPaths = @[[UIBezierPath bezierPathWithRect:CGRectMake(50, 20, 30, 40)]]; - CGSize sizeWithExclusionPaths = [_textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size; + CGSize sizeWithExclusionPaths = [_textNode measure:constrainedSize]; XCTAssertGreaterThan(sizeWithExclusionPaths.height, sizeWithoutExclusionPaths.height, @"Setting exclusions paths should invalidate the calculated size and return a greater size"); } diff --git a/Base/ASBaseDefines.h b/Base/ASBaseDefines.h index dd76c220..1800011d 100755 --- a/Base/ASBaseDefines.h +++ b/Base/ASBaseDefines.h @@ -151,5 +151,3 @@ #define AS_UNAVAILABLE(message) #endif #endif - -#define ASOVERLOADABLE __attribute__((overloadable)) diff --git a/examples/ASDKLayoutTransition/Sample/ViewController.m b/examples/ASDKLayoutTransition/Sample/ViewController.m index 8b746506..1bda2a93 100644 --- a/examples/ASDKLayoutTransition/Sample/ViewController.m +++ b/examples/ASDKLayoutTransition/Sample/ViewController.m @@ -192,7 +192,7 @@ { [super viewDidLayoutSubviews]; - CGSize size = [self.transitionNode layoutThatFits:ASSizeRangeMake(CGSizeZero, self.view.frame.size)].size; + CGSize size = [self.transitionNode measure:self.view.frame.size]; self.transitionNode.frame = CGRectMake(0, 20, size.width, size.height); } diff --git a/examples/ASDKTube/Sample/Nodes/VideoContentCell.m b/examples/ASDKTube/Sample/Nodes/VideoContentCell.m index 3850275a..34e16b5e 100644 --- a/examples/ASDKTube/Sample/Nodes/VideoContentCell.m +++ b/examples/ASDKTube/Sample/Nodes/VideoContentCell.m @@ -65,8 +65,7 @@ [self addSubnode:_likeButtonNode]; _muteButtonNode = [[ASButtonNode alloc] init]; - _muteButtonNode.width = ASDimensionMakeWithPoints(16.0); - _muteButtonNode.height = ASDimensionMakeWithPoints(22.0); + _muteButtonNode.preferredFrameSize = CGSizeMake(16.0, 22.0); [_muteButtonNode addTarget:self action:@selector(didTapMuteButton) forControlEvents:ASControlNodeEventTouchUpInside]; _videoPlayerNode = [[ASVideoPlayerNode alloc] initWithUrl:_videoModel.url loadAssetWhenNodeBecomesVisible:YES]; @@ -87,18 +86,12 @@ }; } -- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +- (ASLayoutSpec*)layoutSpecThatFits:(ASSizeRange)constrainedSize { CGFloat fullWidth = [UIScreen mainScreen].bounds.size.width; - - _videoPlayerNode.width = ASDimensionMakeWithPoints(fullWidth); - _videoPlayerNode.height = ASDimensionMakeWithPoints(fullWidth * 9 / 16); - - _avatarNode.width = ASDimensionMakeWithPoints(AVATAR_IMAGE_HEIGHT); - _avatarNode.height = ASDimensionMakeWithPoints(AVATAR_IMAGE_HEIGHT); - - _likeButtonNode.width = ASDimensionMakeWithPoints(50.0); - _likeButtonNode.height = ASDimensionMakeWithPoints(26.0); + _videoPlayerNode.preferredFrameSize = CGSizeMake(fullWidth, fullWidth * 9 / 16); + _avatarNode.preferredFrameSize = CGSizeMake(AVATAR_IMAGE_HEIGHT, AVATAR_IMAGE_HEIGHT); + _likeButtonNode.preferredFrameSize = CGSizeMake(50.0, 26.0); ASStackLayoutSpec *headerStack = [ASStackLayoutSpec horizontalStackLayoutSpec]; headerStack.spacing = HORIZONTAL_BUFFER; @@ -111,15 +104,15 @@ ASStackLayoutSpec *bottomControlsStack = [ASStackLayoutSpec horizontalStackLayoutSpec]; bottomControlsStack.spacing = HORIZONTAL_BUFFER; bottomControlsStack.alignItems = ASStackLayoutAlignItemsCenter; - bottomControlsStack.children = @[_likeButtonNode]; + [bottomControlsStack setChildren:@[ _likeButtonNode]]; - UIEdgeInsets bottomControlsInsets = UIEdgeInsetsMake(HORIZONTAL_BUFFER, HORIZONTAL_BUFFER, HORIZONTAL_BUFFER, HORIZONTAL_BUFFER); + UIEdgeInsets bottomControlsInsets = UIEdgeInsetsMake(HORIZONTAL_BUFFER, HORIZONTAL_BUFFER, HORIZONTAL_BUFFER, HORIZONTAL_BUFFER); ASInsetLayoutSpec *bottomControlsInset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:bottomControlsInsets child:bottomControlsStack]; - ASStackLayoutSpec *verticalStack = [ASStackLayoutSpec verticalStackLayoutSpec]; - verticalStack.alignItems = ASStackLayoutAlignItemsStretch; - verticalStack.children = @[headerInset, _videoPlayerNode, bottomControlsInset]; + ASStackLayoutSpec *verticalStack = [ASStackLayoutSpec verticalStackLayoutSpec]; + verticalStack.alignItems = ASStackLayoutAlignItemsStretch; + [verticalStack setChildren:@[ headerInset, _videoPlayerNode, bottomControlsInset ]]; return verticalStack; } @@ -190,10 +183,7 @@ if (controls[ @(ASVideoPlayerNodeControlTypeScrubber) ]) { ASDisplayNode *scrubber = controls[ @(ASVideoPlayerNodeControlTypeScrubber) ]; - scrubber.height = ASDimensionMakeWithPoints(44.0); - scrubber.minWidth = ASDimensionMakeWithPoints(0.0); - scrubber.maxWidth = ASDimensionMakeWithPoints(maxSize.width); - scrubber.flexGrow = YES; + scrubber.preferredFrameSize = CGSizeMake(maxSize.width, 44.0); } NSArray *controlBarControls = [self controlsForControlBar:controls]; diff --git a/examples/ASDKgram/Sample/PhotoCellNode.m b/examples/ASDKgram/Sample/PhotoCellNode.m index 8d987318..bbb3cbd4 100644 --- a/examples/ASDKgram/Sample/PhotoCellNode.m +++ b/examples/ASDKgram/Sample/PhotoCellNode.m @@ -126,9 +126,7 @@ // header stack - // constrain avatar image frame size - _userAvatarImageView.width = ASDimensionMakeWithPoints(USER_IMAGE_HEIGHT); - _userAvatarImageView.height = ASDimensionMakeWithPoints(USER_IMAGE_HEIGHT); + _userAvatarImageView.preferredFrameSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); // constrain avatar image frame size _photoTimeIntervalSincePostLabel.spacingBefore = HORIZONTAL_BUFFER; // to remove double spaces around spacer ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init]; // FIXME: long locations overflow post time - set max size? @@ -157,10 +155,7 @@ // vertical stack CGFloat cellWidth = constrainedSize.max.width; - - // constrain photo frame size - _photoImageView.width = ASDimensionMakeWithPoints(cellWidth); - _photoImageView.height = ASDimensionMakeWithPoints(cellWidth); + _photoImageView.preferredFrameSize = CGSizeMake(cellWidth, cellWidth); // constrain photo frame size ASStackLayoutSpec *verticalStack = [ASStackLayoutSpec verticalStackLayoutSpec]; verticalStack.alignItems = ASStackLayoutAlignItemsStretch; // stretch headerStack to fill horizontal space diff --git a/examples/ASMapNode/Sample/MapHandlerNode.m b/examples/ASMapNode/Sample/MapHandlerNode.m index 593f5ff2..fc55eb6b 100644 --- a/examples/ASMapNode/Sample/MapHandlerNode.m +++ b/examples/ASMapNode/Sample/MapHandlerNode.m @@ -115,86 +115,66 @@ { #define SPACING 5 #define HEIGHT 30 - CGSize nodeSize = CGSizeMake(constrainedSize.max.width * 0.3, HEIGHT); + CGSize preferredSize = CGSizeMake(constrainedSize.max.width * 0.3, HEIGHT); - [_latEditableNode setSizeWithCGSize:nodeSize]; - [_lonEditableNode setSizeWithCGSize:nodeSize]; - - [_deltaLatEditableNode setSizeWithCGSize:nodeSize]; - [_deltaLonEditableNode setSizeWithCGSize:nodeSize]; - - [_updateRegionButton setSizeWithCGSize:nodeSize]; - [_liveMapToggleButton setSizeWithCGSize:nodeSize]; + _latEditableNode.preferredFrameSize = _lonEditableNode.preferredFrameSize = preferredSize; + _deltaLatEditableNode.preferredFrameSize = _deltaLonEditableNode.preferredFrameSize = preferredSize; + _updateRegionButton.preferredFrameSize = _liveMapToggleButton.preferredFrameSize = preferredSize; - _latEditableNode.flexGrow = _lonEditableNode.flexGrow = YES; - _deltaLatEditableNode.flexGrow = _deltaLonEditableNode.flexGrow = YES; - _updateRegionButton.flexGrow = _liveMapToggleButton.flexGrow = YES; + _latEditableNode.flexGrow = _lonEditableNode.flexGrow = true; + _deltaLatEditableNode.flexGrow = _deltaLonEditableNode.flexGrow = true; + _updateRegionButton.flexGrow = _liveMapToggleButton.flexGrow = true; - _mapNode.flexGrow = YES; + _mapNode.flexGrow = true; - ASStackLayoutSpec *lonlatSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:SPACING - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsCenter - children:@[_latEditableNode, _lonEditableNode]]; + ASStackLayoutSpec * lonlatSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal + spacing:SPACING + justifyContent:ASStackLayoutJustifyContentStart + alignItems:ASStackLayoutAlignItemsCenter + children:@[_latEditableNode, _lonEditableNode]]; lonlatSpec.flexGrow = true; - ASStackLayoutSpec *deltaLonlatSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:SPACING - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsCenter - children:@[_deltaLatEditableNode, _deltaLonEditableNode]]; + ASStackLayoutSpec * deltaLonlatSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal + spacing:SPACING + justifyContent:ASStackLayoutJustifyContentStart + alignItems:ASStackLayoutAlignItemsCenter + children:@[_deltaLatEditableNode, _deltaLonEditableNode]]; deltaLonlatSpec.flexGrow = true; - ASStackLayoutSpec *lonlatConfigSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical - spacing:SPACING - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStretch - children:@[lonlatSpec, deltaLonlatSpec]]; + ASStackLayoutSpec * lonlatConfigSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical + spacing:SPACING + justifyContent:ASStackLayoutJustifyContentStart + alignItems:ASStackLayoutAlignItemsStretch + children:@[lonlatSpec, deltaLonlatSpec]]; lonlatConfigSpec.flexGrow = true; - ASStackLayoutSpec *buttonsSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical - spacing:SPACING - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStretch - children:@[_updateRegionButton, _liveMapToggleButton]]; + ASStackLayoutSpec * buttonsSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical + spacing:SPACING + justifyContent:ASStackLayoutJustifyContentStart + alignItems:ASStackLayoutAlignItemsStretch + children:@[_updateRegionButton, _liveMapToggleButton]]; buttonsSpec.flexGrow = true; - ASStackLayoutSpec *dashboardSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:SPACING - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStretch - children:@[lonlatConfigSpec, buttonsSpec]]; + ASStackLayoutSpec * dashboardSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal + spacing:SPACING + justifyContent:ASStackLayoutJustifyContentStart + alignItems:ASStackLayoutAlignItemsStretch + children:@[lonlatConfigSpec, buttonsSpec]]; dashboardSpec.flexGrow = true; - ASInsetLayoutSpec *insetSpec = - [ASInsetLayoutSpec - insetLayoutSpecWithInsets:UIEdgeInsetsMake(20, 10, 0, 10) - child:dashboardSpec]; + ASInsetLayoutSpec * insetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(20, 10, 0, 10) child:dashboardSpec]; - ASStackLayoutSpec *layoutSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical - spacing:SPACING - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStretch - children:@[insetSpec, _mapNode ]]; + ASStackLayoutSpec * layoutSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical + spacing:SPACING + justifyContent:ASStackLayoutJustifyContentStart + alignItems:ASStackLayoutAlignItemsStretch + children:@[insetSpec, _mapNode ]]; return layoutSpec; } #pragma mark - Button actions -- (void)updateRegion +-(void)updateRegion { NSNumberFormatter *f = [[NSNumberFormatter alloc] init]; f.numberStyle = NSNumberFormatterDecimalStyle; @@ -210,7 +190,7 @@ _mapNode.region = region; } -- (void)toggleLiveMap +-(void)toggleLiveMap { _mapNode.liveMap = !_mapNode.liveMap; NSString * const liveMapStr = [self liveMapStr]; diff --git a/examples/ASViewController/Sample/DetailCellNode.m b/examples/ASViewController/Sample/DetailCellNode.m index c8448557..47016ab8 100644 --- a/examples/ASViewController/Sample/DetailCellNode.m +++ b/examples/ASViewController/Sample/DetailCellNode.m @@ -39,7 +39,7 @@ - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { self.imageNode.position = CGPointZero; - [self.imageNode setSizeWithCGSize:constrainedSize.max]; + self.imageNode.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(constrainedSize.max); return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.imageNode]]; } diff --git a/examples/ASViewController/Sample/DetailRootNode.m b/examples/ASViewController/Sample/DetailRootNode.m index 42679704..658a9b78 100644 --- a/examples/ASViewController/Sample/DetailRootNode.m +++ b/examples/ASViewController/Sample/DetailRootNode.m @@ -63,7 +63,7 @@ static const NSInteger kImageHeight = 200; - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { self.collectionNode.position = CGPointZero; - [self.collectionNode setSizeWithCGSize:constrainedSize.max]; + self.collectionNode.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(constrainedSize.max); return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.collectionNode]]; } diff --git a/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASCollectionNode.m b/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASCollectionNode.m index 42d3b9a0..d406f3b1 100644 --- a/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASCollectionNode.m +++ b/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASCollectionNode.m @@ -45,10 +45,8 @@ - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - // 100% of container - _node.width = ASDimensionMakeWithFraction(1.0); - _node.height = ASDimensionMakeWithFraction(1.0); - return [ASWrapperLayoutSpec wrapperWithLayoutable:_node]; + self.node.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(constrainedSize.max); + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.node]]; } #pragma mark - diff --git a/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASPagerNode.m b/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASPagerNode.m index 7b06ef54..b2a4499b 100644 --- a/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASPagerNode.m +++ b/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASPagerNode.m @@ -37,7 +37,9 @@ static UIColor *OverViewASPagerNodeRandomColor() { - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize { - return [ASLayout layoutWithLayoutable:self size:constrainedSize.max]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:constrainedSize.max]; } @end @@ -67,10 +69,8 @@ static UIColor *OverViewASPagerNodeRandomColor() { - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - // 100% of container - _node.width = ASDimensionMakeWithFraction(1.0); - _node.height = ASDimensionMakeWithFraction(1.0); - return [ASWrapperLayoutSpec wrapperWithLayoutable:_node]; + _node.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(constrainedSize.max); + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[_node]]; } - (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode diff --git a/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASTableNode.m b/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASTableNode.m index 25cd559d..fc31b59f 100644 --- a/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASTableNode.m +++ b/examples/AsyncDisplayKitOverview/Sample/Node Containers/OverviewASTableNode.m @@ -42,10 +42,8 @@ - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - // 100% of container - _node.width = ASDimensionMakeWithFraction(1.0); - _node.height = ASDimensionMakeWithFraction(1.0); - return [ASWrapperLayoutSpec wrapperWithLayoutable:_node]; + _node.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(constrainedSize.max); + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[_node]]; } diff --git a/examples/AsyncDisplayKitOverview/Sample/OverviewComponentsViewController.m b/examples/AsyncDisplayKitOverview/Sample/OverviewComponentsViewController.m index 1cfacbb5..853b2ecc 100644 --- a/examples/AsyncDisplayKitOverview/Sample/OverviewComponentsViewController.m +++ b/examples/AsyncDisplayKitOverview/Sample/OverviewComponentsViewController.m @@ -82,7 +82,6 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr BOOL hasDescription = self.descriptionNode.attributedText.length > 0; ASStackLayoutSpec *verticalStackLayoutSpec = [ASStackLayoutSpec verticalStackLayoutSpec]; - verticalStackLayoutSpec.alignItems = ASStackLayoutAlignItemsStart; verticalStackLayoutSpec.spacing = 5.0; verticalStackLayoutSpec.children = hasDescription ? @[self.titleNode, self.descriptionNode] : @[self.titleNode]; @@ -204,11 +203,8 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr #pragma mark ASImageNode ASImageNode *imageNode = [ASImageNode new]; - imageNode.image = [UIImage imageNamed:@"image.jpg"]; - - CGSize imageNetworkImageNodeSize = (CGSize){imageNode.image.size.width / 7, imageNode.image.size.height / 7}; - - [imageNode setSizeWithCGSize:imageNetworkImageNodeSize]; + imageNode.image = [UIImage imageNamed:@"image"]; + imageNode.preferredFrameSize = CGSizeMake(imageNode.image.size.width / 7, imageNode.image.size.height / 7); parentNode = [self centeringParentNodeWithChild:imageNode]; parentNode.entryTitle = @"ASImageNode"; @@ -218,7 +214,7 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr #pragma mark ASNetworkImageNode ASNetworkImageNode *networkImageNode = [ASNetworkImageNode new]; networkImageNode.URL = [NSURL URLWithString:@"http://i.imgur.com/FjOR9kX.jpg"]; - [networkImageNode setSizeWithCGSize:imageNetworkImageNodeSize]; + networkImageNode.preferredFrameSize = CGSizeMake(imageNode.image.size.width / 7, imageNode.image.size.height / 7); parentNode = [self centeringParentNodeWithChild:networkImageNode]; parentNode.entryTitle = @"ASNetworkImageNode"; @@ -227,7 +223,7 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr #pragma mark ASMapNode ASMapNode *mapNode = [ASMapNode new]; - [mapNode setSizeWithCGSize:(CGSize){300.0, 300.0}]; + mapNode.preferredFrameSize = CGSizeMake(300.0, 300.0); // San Francisco CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(37.7749, -122.4194); @@ -240,7 +236,7 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr #pragma mark ASVideoNode ASVideoNode *videoNode = [ASVideoNode new]; - [videoNode setSizeWithCGSize:(CGSize){300.0, 400.0}]; + videoNode.preferredFrameSize = CGSizeMake(300.0, 400.0); AVAsset *asset = [AVAsset assetWithURL:[NSURL URLWithString:@"http://www.w3schools.com/html/mov_bbb.mp4"]]; videoNode.asset = asset; @@ -254,7 +250,7 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr UIImage *scrollNodeImage = [UIImage imageNamed:@"image"]; ASScrollNode *scrollNode = [ASScrollNode new]; - [scrollNode setSizeWithCGSize:(CGSize){300.0, 400.0}]; + scrollNode.preferredFrameSize = CGSizeMake(300.0, 400.0); UIScrollView *scrollNodeView = scrollNode.view; [scrollNodeView addSubview:[[UIImageView alloc] initWithImage:scrollNodeImage]]; @@ -395,7 +391,6 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr parentNode.entryDescription = @"Is based on a simplified version of CSS flexbox. It allows you to stack components vertically or horizontally and specify how they should be flexed and aligned to fit in the available space."; parentNode.sizeThatFitsBlock = ^ASLayoutSpec *(ASSizeRange constrainedSize) { ASStackLayoutSpec *verticalStackLayoutSpec = [ASStackLayoutSpec verticalStackLayoutSpec]; - verticalStackLayoutSpec.alignItems = ASStackLayoutAlignItemsStart; verticalStackLayoutSpec.children = @[childNode1, childNode2, childNode3]; return verticalStackLayoutSpec; }; @@ -406,17 +401,17 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr #pragma mark Horizontal ASStackLayoutSpec childNode1 = [ASDisplayNode new]; - [childNode1 setSizeWithCGSize:(CGSize){10.0, 20.0}]; + childNode1.preferredFrameSize = CGSizeMake(10.0, 20); childNode1.flexGrow = YES; childNode1.backgroundColor = [UIColor greenColor]; childNode2 = [ASDisplayNode new]; - [childNode2 setSizeWithCGSize:(CGSize){10.0, 20.0}]; + childNode2.preferredFrameSize = CGSizeMake(10.0, 20.0); childNode2.alignSelf = ASStackLayoutAlignSelfStretch; childNode2.backgroundColor = [UIColor blueColor]; childNode3 = [ASDisplayNode new]; - [childNode3 setSizeWithCGSize:(CGSize){10.0, 20.0}]; + childNode3.preferredFrameSize = CGSizeMake(10.0, 20.0); childNode3.backgroundColor = [UIColor yellowColor]; parentNode = [self parentNodeWithChild:childNode]; @@ -425,17 +420,20 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr parentNode.sizeThatFitsBlock = ^ASLayoutSpec *(ASSizeRange constrainedSize) { // Create stack alyout spec to layout children - ASStackLayoutSpec *horizontalStackSpec = [ASStackLayoutSpec horizontalStackLayoutSpec]; - horizontalStackSpec.alignItems = ASStackLayoutAlignItemsStart; - horizontalStackSpec.children = @[childNode1, childNode2, childNode3]; - horizontalStackSpec.spacing = 5.0; // Spacing between children + ASStackLayoutSpec *verticalStackLayoutSpec = [ASStackLayoutSpec horizontalStackLayoutSpec]; + verticalStackLayoutSpec.children = @[childNode1, childNode2, childNode3]; + verticalStackLayoutSpec.spacing = 5.0; // Spacing between children // Layout the stack layout with 100% width and 100% height of the parent node - horizontalStackSpec.height = ASDimensionMakeWithFraction(1.0); - horizontalStackSpec.width = ASDimensionMakeWithFraction(1.0); + ASRelativeSizeRange sizeRange = ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimensionMakeWithFraction(1), + ASRelativeDimensionMakeWithFraction(1)); + verticalStackLayoutSpec.sizeRange = sizeRange; + + // Wrap the static stack layout in a static spec so it will grow to the whole parent node size + ASStaticLayoutSpec *staticLayoutSpec = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[verticalStackLayoutSpec]]; // Add a bit of inset - return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(0.0, 5.0, 0.0, 5.0) child:horizontalStackSpec]; + return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(0.0, 5.0, 0.0, 5.0) child:staticLayoutSpec]; }; [parentNode addSubnode:childNode1]; [parentNode addSubnode:childNode2]; @@ -467,7 +465,7 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr - (OverviewDisplayNodeWithSizeBlock *)parentNodeWithChild:(ASDisplayNode *)child { OverviewDisplayNodeWithSizeBlock *parentNode = [OverviewDisplayNodeWithSizeBlock new]; - [parentNode setSizeWithCGSize:(CGSize){100, 100}]; + parentNode.preferredFrameSize = CGSizeMake(100, 100); parentNode.backgroundColor = [UIColor redColor]; return parentNode; } @@ -491,7 +489,7 @@ typedef ASLayoutSpec *(^OverviewDisplayNodeSizeThatFitsBlock)(ASSizeRange constr - (ASDisplayNode *)childNode { ASDisplayNode *childNode = [ASDisplayNode new]; - [childNode setSizeWithCGSize:(CGSize){50, 50}]; + childNode.preferredFrameSize = CGSizeMake(50, 50); childNode.backgroundColor = [UIColor blueColor]; return childNode; } diff --git a/examples/AsyncDisplayKitOverview/Sample/OverviewDetailViewController.m b/examples/AsyncDisplayKitOverview/Sample/OverviewDetailViewController.m index af2a39cb..c5bfdb14 100644 --- a/examples/AsyncDisplayKitOverview/Sample/OverviewDetailViewController.m +++ b/examples/AsyncDisplayKitOverview/Sample/OverviewDetailViewController.m @@ -51,11 +51,12 @@ // Center node frame CGRect bounds = self.view.bounds; - CGSize nodeSize = [self.node layoutThatFits:ASSizeRangeMake(CGSizeZero, bounds.size)].size; - self.node.frame = CGRectMake(CGRectGetMidX(bounds) - (nodeSize.width / 2.0), - CGRectGetMidY(bounds) - (nodeSize.height / 2.0), - nodeSize.width, - nodeSize.height); + CGSize nodeSize = self.node.preferredFrameSize; + if (CGSizeEqualToSize(nodeSize, CGSizeZero)) { + nodeSize = self.view.bounds.size; + } + self.node.frame = CGRectMake(CGRectGetMidX(bounds) - (nodeSize.width / 2.0), CGRectGetMidY(bounds) - (nodeSize.height / 2.0), nodeSize.width, nodeSize.height); + [self.node measure:self.node.bounds.size]; } @end diff --git a/examples/CatDealsCollectionView/Sample/ItemNode.m b/examples/CatDealsCollectionView/Sample/ItemNode.m index 4874f338..8515cc8f 100644 --- a/examples/CatDealsCollectionView/Sample/ItemNode.m +++ b/examples/CatDealsCollectionView/Sample/ItemNode.m @@ -107,8 +107,7 @@ const CGFloat kSoldOutGBHeight = 50.0; self.soldOutLabelFlat.layerBacked = YES; self.soldOutLabelBackground = [[ASDisplayNode alloc] init]; - self.soldOutLabelBackground.width = ASDimensionMakeWithFraction(1.0); - self.soldOutLabelBackground.height = ASDimensionMakeWithPoints(kSoldOutGBHeight); + self.soldOutLabelBackground.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMake(ASRelativeDimensionMakeWithFraction(1), ASRelativeDimensionMakeWithPoints(kSoldOutGBHeight)), ASRelativeSizeMake(ASRelativeDimensionMakeWithFraction(1), ASRelativeDimensionMakeWithPoints(kSoldOutGBHeight))); self.soldOutLabelBackground.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9]; self.soldOutLabelBackground.flexGrow = YES; self.soldOutLabelBackground.layerBacked = YES; @@ -290,7 +289,7 @@ const CGFloat kSoldOutGBHeight = 50.0; ASRatioLayoutSpec *imagePlace = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:imageRatio child:self.dealImageView]; self.badge.layoutPosition = CGPointMake(0, constrainedSize.max.height - kFixedLabelsAreaHeight - kBadgeHeight); - self.badge.height = ASDimensionMakeWithPoints(kBadgeHeight); + self.badge.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMake(ASRelativeDimensionMakeWithFraction(0), ASRelativeDimensionMakeWithPoints(kBadgeHeight)), ASRelativeSizeMake(ASRelativeDimensionMakeWithFraction(1), ASRelativeDimensionMakeWithPoints(kBadgeHeight))); ASStaticLayoutSpec *badgePosition = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.badge]]; ASOverlayLayoutSpec *badgeOverImage = [ASOverlayLayoutSpec overlayLayoutSpecWithChild:imagePlace overlay:badgePosition]; @@ -301,7 +300,8 @@ const CGFloat kSoldOutGBHeight = 50.0; - (ASLayoutSpec *)soldOutLabelSpec { ASCenterLayoutSpec *centerSoldOutLabel = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY child:self.soldOutLabelFlat]; - ASCenterLayoutSpec *centerSoldOut = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:self.soldOutLabelBackground]; + ASStaticLayoutSpec *soldOutBG = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.soldOutLabelBackground]]; + ASCenterLayoutSpec *centerSoldOut = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:soldOutBG]; ASBackgroundLayoutSpec *soldOutLabelOverBackground = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:centerSoldOutLabel background:centerSoldOut]; return soldOutLabelOverBackground; } diff --git a/examples/CatDealsCollectionView/Sample/LoadingNode.m b/examples/CatDealsCollectionView/Sample/LoadingNode.m index dafc883d..43a76937 100644 --- a/examples/CatDealsCollectionView/Sample/LoadingNode.m +++ b/examples/CatDealsCollectionView/Sample/LoadingNode.m @@ -53,8 +53,9 @@ static CGFloat kFixedHeight = 200.0f; [spinner startAnimating]; return spinner; }]; - [_loadingSpinner setSizeWithCGSize:CGSizeMake(50, 50)]; - + _loadingSpinner.preferredFrameSize = CGSizeMake(50, 50); + + // add it as a subnode, and we're done [self addSubnode:_loadingSpinner]; diff --git a/examples/CustomCollectionView/Sample/ImageCellNode.m b/examples/CustomCollectionView/Sample/ImageCellNode.m index 73b1d373..5eb7163c 100644 --- a/examples/CustomCollectionView/Sample/ImageCellNode.m +++ b/examples/CustomCollectionView/Sample/ImageCellNode.m @@ -34,9 +34,17 @@ return self; } -- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { - return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:_imageNode]; + [_imageNode measure:constrainedSize]; + return constrainedSize; +} + +- (void)layout +{ + [super layout]; + + _imageNode.frame = CGRectMake(0, 0, _imageNode.calculatedSize.width, _imageNode.calculatedSize.height); } @end diff --git a/examples/HorizontalWithinVerticalScrolling/Sample/HorizontalScrollCellNode.mm b/examples/HorizontalWithinVerticalScrolling/Sample/HorizontalScrollCellNode.mm index b5ba0888..a7b59895 100644 --- a/examples/HorizontalWithinVerticalScrolling/Sample/HorizontalScrollCellNode.mm +++ b/examples/HorizontalWithinVerticalScrolling/Sample/HorizontalScrollCellNode.mm @@ -64,7 +64,6 @@ static const CGFloat kInnerPadding = 10.0f; - (void)didLoad { [super didLoad]; - _collectionNode.view.asyncDelegate = self; _collectionNode.view.asyncDataSource = self; } @@ -76,22 +75,21 @@ static const CGFloat kInnerPadding = 10.0f; - (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath { - CGSize elementSize = _elementSize; return ^{ RandomCoreGraphicsNode *elementNode = [[RandomCoreGraphicsNode alloc] init]; - [elementNode setSizeWithCGSize:elementSize]; + elementNode.preferredFrameSize = _elementSize; return elementNode; }; } - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - CGSize collectionNodeSize = CGSizeMake(constrainedSize.max.width, _elementSize.height); - [_collectionNode setSizeWithCGSize:collectionNodeSize]; + _collectionNode.preferredFrameSize = CGSizeMake(self.bounds.size.width, _elementSize.height); ASInsetLayoutSpec *insetSpec = [[ASInsetLayoutSpec alloc] init]; insetSpec.insets = UIEdgeInsetsMake(kOuterPadding, 0.0, kOuterPadding, 0.0); insetSpec.child = _collectionNode; + return insetSpec; } diff --git a/examples/HorizontalWithinVerticalScrolling/Sample/ViewController.m b/examples/HorizontalWithinVerticalScrolling/Sample/ViewController.m index fbc1cd7e..0f3afbae 100644 --- a/examples/HorizontalWithinVerticalScrolling/Sample/ViewController.m +++ b/examples/HorizontalWithinVerticalScrolling/Sample/ViewController.m @@ -68,11 +68,13 @@ _tableView.frame = self.view.bounds; } -#pragma mark - ASTableView. +#pragma mark - +#pragma mark ASTableView. - (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath { - return [[HorizontalScrollCellNode alloc] initWithElementSize:CGSizeMake(100, 100)]; + HorizontalScrollCellNode *node = [[HorizontalScrollCellNode alloc] initWithElementSize:CGSizeMake(100, 100)]; + return node; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index f75fc101..e97ef637 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -98,7 +98,8 @@ static const CGFloat kInnerPadding = 10.0f; // lorem ipsum text, plus some nice styling _textNode = [[ASTextNode alloc] init]; - _textNode.attributedText = [[NSAttributedString alloc] initWithString:[self kittyIpsum] attributes:[self textStyle]]; + _textNode.attributedText = [[NSAttributedString alloc] initWithString:[self kittyIpsum] + attributes:[self textStyle]]; [self addSubnode:_textNode]; // hairline cell separator @@ -133,36 +134,27 @@ static const CGFloat kInnerPadding = 10.0f; style.paragraphSpacing = 0.5 * font.lineHeight; style.hyphenationFactor = 1.0; - return @{ - NSFontAttributeName: font, - NSParagraphStyleAttributeName: style, - ASTextNodeWordKerningAttributeName : @.5 - }; + return @{ NSFontAttributeName: font, + NSParagraphStyleAttributeName: style, + ASTextNodeWordKerningAttributeName : @.5}; } #if UseAutomaticLayout - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - // Set an intrinsic size for the image node - CGSize imageSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); - [_imageNode setSizeWithCGSize:imageSize]; - - // Shrink the text node in case the image + text gonna be too wide + _imageNode.preferredFrameSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); _textNode.flexShrink = YES; - - // Configure stack - ASStackLayoutSpec *stackLayoutSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:kInnerPadding - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStart - children:_swappedTextAndImage ? @[_textNode, _imageNode] : @[_imageNode, _textNode]]; - // Add inset - return [ASInsetLayoutSpec - insetLayoutSpecWithInsets:UIEdgeInsetsMake(kOuterPadding, kOuterPadding, kOuterPadding, kOuterPadding) - child:stackLayoutSpec]; + ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; + stackSpec.direction = ASStackLayoutDirectionHorizontal; + stackSpec.spacing = kInnerPadding; + [stackSpec setChildren:!_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. diff --git a/examples/PagerNode/Sample/PageNode.m b/examples/PagerNode/Sample/PageNode.m index 264809ce..4db8e4f9 100644 --- a/examples/PagerNode/Sample/PageNode.m +++ b/examples/PagerNode/Sample/PageNode.m @@ -23,7 +23,9 @@ - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize { - return [ASLayout layoutWithLayoutable:self size:constrainedSize.max]; + return [ASLayout layoutWithLayoutableObject:self + constrainedSizeRange:constrainedSize + size:constrainedSize.max]; } - (void)fetchData diff --git a/examples/SocialAppLayout/Sample/CommentsNode.m b/examples/SocialAppLayout/Sample/CommentsNode.m index 33ad608f..de1a0099 100644 --- a/examples/SocialAppLayout/Sample/CommentsNode.m +++ b/examples/SocialAppLayout/Sample/CommentsNode.m @@ -52,19 +52,13 @@ - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - ASStackLayoutSpec *mainStack = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:6.0 - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsCenter - children:@[_iconNode, _countNode]]; + ASStackLayoutSpec *mainStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:6.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsCenter children:@[self.iconNode, self.countNode]]; - // Adjust size - mainStack.minWidth = ASDimensionMakeWithPoints(60.0); - mainStack.maxHeight = ASDimensionMakeWithPoints(40.0); - - return mainStack; + // set sizeRange to make width fixed to 60 + ASRelativeSize min = ASRelativeSizeMake(ASRelativeDimensionMakeWithPoints(60.0), ASRelativeDimensionMakeWithPoints(0.0)); + ASRelativeSize max = ASRelativeSizeMake(ASRelativeDimensionMakeWithPoints(60.0), ASRelativeDimensionMakeWithPoints(40.0)); + mainStack.sizeRange = ASRelativeSizeRangeMake(min,max); + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[mainStack]]; } @end diff --git a/examples/SocialAppLayout/Sample/LikesNode.m b/examples/SocialAppLayout/Sample/LikesNode.m index 041775e5..c0d9d78e 100644 --- a/examples/SocialAppLayout/Sample/LikesNode.m +++ b/examples/SocialAppLayout/Sample/LikesNode.m @@ -66,18 +66,13 @@ - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - ASStackLayoutSpec *mainStack = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:6.0 - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsCenter - children:@[_iconNode, _countNode]]; - - mainStack.minWidth = ASDimensionMakeWithPoints(60.0); - mainStack.maxHeight = ASDimensionMakeWithPoints(40.0); - - return mainStack; + ASStackLayoutSpec *mainStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:6.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsCenter children:@[_iconNode, _countNode]]; + + // set sizeRange to make width fixed to 60 + ASRelativeSize min = ASRelativeSizeMake(ASRelativeDimensionMakeWithPoints(60.0), ASRelativeDimensionMakeWithPoints(0.0)); + ASRelativeSize max = ASRelativeSizeMake(ASRelativeDimensionMakeWithPoints(60.0), ASRelativeDimensionMakeWithPoints(40.0)); + mainStack.sizeRange = ASRelativeSizeRangeMake(min, max); + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[mainStack]]; } @end diff --git a/examples/SocialAppLayout/Sample/PostNode.m b/examples/SocialAppLayout/Sample/PostNode.m index 6b45f2f2..91879996 100644 --- a/examples/SocialAppLayout/Sample/PostNode.m +++ b/examples/SocialAppLayout/Sample/PostNode.m @@ -20,7 +20,6 @@ #import "TextStyles.h" #import "LikesNode.h" #import "CommentsNode.h" -#import "ASRelativeSize.h" #define PostNodeDividerColor [UIColor lightGrayColor] @@ -137,8 +136,7 @@ // User pic _avatarNode = [[ASNetworkImageNode alloc] init]; _avatarNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); - _avatarNode.width = ASDimensionMakeWithPoints(44); - _avatarNode.height = ASDimensionMakeWithPoints(44); + _avatarNode.preferredFrameSize = CGSizeMake(44, 44); _avatarNode.cornerRadius = 22.0; _avatarNode.URL = [NSURL URLWithString:_post.photo]; _avatarNode.imageModificationBlock = ^UIImage *(UIImage *image) { @@ -216,10 +214,7 @@ // NOTE: This inset is not actually required by the layout, but is an example of the upward propogation of layoutable // properties. Specifically, .flexGrow from the child is transferred to the inset spec so they can expand together. // Without this capability, it would be required to set insetSpacer.flexGrow = YES; - ASInsetLayoutSpec *insetSpacer = - [ASInsetLayoutSpec - insetLayoutSpecWithInsets:UIEdgeInsetsMake(0, 0, 0, 0) - child:spacer]; + ASInsetLayoutSpec *insetSpacer = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(0, 0, 0, 0) child:spacer]; // Horizontal stack for name, username, via icon and time NSMutableArray *layoutSpecChildren = [@[_nameNode, _usernameNode, insetSpacer] mutableCopy]; @@ -228,23 +223,11 @@ } [layoutSpecChildren addObject:_timeNode]; - ASStackLayoutSpec *nameStack = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:5.0 - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsCenter - children:layoutSpecChildren]; + ASStackLayoutSpec *nameStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:5.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsCenter children:layoutSpecChildren]; nameStack.alignSelf = ASStackLayoutAlignSelfStretch; // bottom controls horizontal stack - ASStackLayoutSpec *controlsStack = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:10 - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsCenter - children:@[_likesNode, _commentsNode, _optionsNode]]; + ASStackLayoutSpec *controlsStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:10 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsCenter children:@[_likesNode, _commentsNode, _optionsNode]]; // Add more gaps for control line controlsStack.spacingAfter = 3.0; @@ -254,46 +237,26 @@ [mainStackContent addObject:nameStack]; [mainStackContent addObject:_postNode]; - - if (![_post.media isEqualToString:@""]){ + if (![_post.media isEqualToString:@""]) { + CGFloat imageRatio = (_mediaNode.image != nil ? _mediaNode.image.size.height / _mediaNode.image.size.width : 0.5); + ASRatioLayoutSpec *imagePlace = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:imageRatio child:_mediaNode]; + imagePlace.spacingAfter = 3.0; + imagePlace.spacingBefore = 3.0; + + [mainStackContent addObject:imagePlace]; - // Only add the media node if an image is present - if (_mediaNode.image != nil) { - CGFloat imageRatio = (_mediaNode.image != nil ? _mediaNode.image.size.height / _mediaNode.image.size.width : 0.5); - ASRatioLayoutSpec *imagePlace = - [ASRatioLayoutSpec - ratioLayoutSpecWithRatio:imageRatio - child:_mediaNode]; - imagePlace.spacingAfter = 3.0; - imagePlace.spacingBefore = 3.0; - - [mainStackContent addObject:imagePlace]; - } } [mainStackContent addObject:controlsStack]; // Vertical spec of cell main content - ASStackLayoutSpec *contentSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical - spacing:8.0 - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStretch - children:mainStackContent]; + ASStackLayoutSpec *contentSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:8.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:mainStackContent]; + contentSpec.alignItems = ASStackLayoutAlignSelfStretch; contentSpec.flexShrink = YES; // Horizontal spec for avatar - ASStackLayoutSpec *avatarContentSpec = - [ASStackLayoutSpec - stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal - spacing:8.0 - justifyContent:ASStackLayoutJustifyContentStart - alignItems:ASStackLayoutAlignItemsStart - children:@[_avatarNode, contentSpec]]; + ASStackLayoutSpec *avatarContentSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:8.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[_avatarNode, contentSpec]]; - return [ASInsetLayoutSpec - insetLayoutSpecWithInsets:UIEdgeInsetsMake(10, 10, 10, 10) - child:avatarContentSpec]; + return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(10, 10, 10, 10) child:avatarContentSpec]; } diff --git a/examples/SocialAppLayout/Sample/ViewController.m b/examples/SocialAppLayout/Sample/ViewController.m index 492861c0..9a2692f5 100644 --- a/examples/SocialAppLayout/Sample/ViewController.m +++ b/examples/SocialAppLayout/Sample/ViewController.m @@ -55,7 +55,7 @@ { [super viewDidLoad]; - self.tableView = [[ASTableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; + self.tableView = [[ASTableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain asyncDataFetching:YES]; self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; // SocialAppNode has its own separator self.tableView.asyncDataSource = self; diff --git a/examples/Swift/Sample/AppDelegate.swift b/examples/Swift/Sample/AppDelegate.swift index 2aaa33f9..7bcf44e4 100644 --- a/examples/Swift/Sample/AppDelegate.swift +++ b/examples/Swift/Sample/AppDelegate.swift @@ -25,7 +25,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { let window = UIWindow(frame: UIScreen.mainScreen().bounds) window.backgroundColor = UIColor.whiteColor() - window.rootViewController = UINavigationController(rootViewController: ViewController()); + window.rootViewController = ViewController() window.makeKeyAndVisible() self.window = window return true diff --git a/examples/Swift/Sample/TailLoadingCellNode.swift b/examples/Swift/Sample/TailLoadingCellNode.swift index 101b3033..6defdbd2 100644 --- a/examples/Swift/Sample/TailLoadingCellNode.swift +++ b/examples/Swift/Sample/TailLoadingCellNode.swift @@ -54,8 +54,7 @@ final class SpinnerNode: ASDisplayNode { override init() { super.init(viewBlock: { UIActivityIndicatorView(activityIndicatorStyle: .Gray) }, didLoadBlock: nil) - - size.minHeight = ASDimensionMakeWithPoints(44.0) + preferredFrameSize.height = 32 } override func didLoad() { diff --git a/examples/Swift/Sample/ViewController.swift b/examples/Swift/Sample/ViewController.swift index 0982081c..a23486bd 100644 --- a/examples/Swift/Sample/ViewController.swift +++ b/examples/Swift/Sample/ViewController.swift @@ -127,15 +127,14 @@ final class ViewController: ASViewController, ASTableDataSource, ASTableDelegate /// (Pretend) fetches some new items and calls the /// completion handler on the main thread. private static func fetchDataWithCompletion(completion: (Int) -> Void) { - let time = dispatch_time(DISPATCH_TIME_NOW, Int64(NSTimeInterval(NSEC_PER_SEC) * 1.0)) + let time = dispatch_time(DISPATCH_TIME_NOW, Int64(NSTimeInterval(NSEC_PER_SEC) * 0.5)) dispatch_after(time, dispatch_get_main_queue()) { let resultCount = Int(arc4random_uniform(20)) completion(resultCount) } } - private static func handleAction(action: Action, fromState state: State) -> State { - var state = state + private static func handleAction(action: Action, var fromState state: State) -> State { switch action { case .BeginBatchFetch: state.fetchingMore = true diff --git a/examples/VerticalWithinHorizontalScrolling/Sample/GradientTableNode.mm b/examples/VerticalWithinHorizontalScrolling/Sample/GradientTableNode.mm index eaa01e7d..d86f831d 100644 --- a/examples/VerticalWithinHorizontalScrolling/Sample/GradientTableNode.mm +++ b/examples/VerticalWithinHorizontalScrolling/Sample/GradientTableNode.mm @@ -68,7 +68,7 @@ - (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath { RandomCoreGraphicsNode *elementNode = [[RandomCoreGraphicsNode alloc] init]; - [elementNode setSizeWithCGSize:_elementSize]; + elementNode.preferredFrameSize = _elementSize; elementNode.indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:_pageNumber]; return elementNode; } diff --git a/examples/VerticalWithinHorizontalScrolling/Sample/RandomCoreGraphicsNode.m b/examples/VerticalWithinHorizontalScrolling/Sample/RandomCoreGraphicsNode.m index 74dd5170..321d04d4 100644 --- a/examples/VerticalWithinHorizontalScrolling/Sample/RandomCoreGraphicsNode.m +++ b/examples/VerticalWithinHorizontalScrolling/Sample/RandomCoreGraphicsNode.m @@ -71,11 +71,17 @@ _indexPathTextNode.attributedText = [[NSAttributedString alloc] initWithString:[indexPath description] attributes:nil]; } +//- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +//{ +// ASStackLayoutSpec *stackSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[_indexPathTextNode]]; +// stackSpec.flexGrow = YES; +// return stackSpec; +//} + - (void)layout { - [super layout]; - _indexPathTextNode.frame = self.bounds; + [super layout]; } #if 0 diff --git a/examples/VerticalWithinHorizontalScrolling/Sample/ViewController.m b/examples/VerticalWithinHorizontalScrolling/Sample/ViewController.m index e7311a33..c474bbbb 100644 --- a/examples/VerticalWithinHorizontalScrolling/Sample/ViewController.m +++ b/examples/VerticalWithinHorizontalScrolling/Sample/ViewController.m @@ -77,7 +77,7 @@ CGSize boundsSize = pagerNode.bounds.size; CGSize gradientRowSize = CGSizeMake(boundsSize.width, 100); GradientTableNode *node = [[GradientTableNode alloc] initWithElementSize:gradientRowSize]; - [node setSizeWithCGSize:boundsSize]; + node.preferredFrameSize = boundsSize; node.pageNumber = index; return node; } diff --git a/examples/Videos/Sample/ViewController.m b/examples/Videos/Sample/ViewController.m index faa4b8b8..1b390386 100644 --- a/examples/Videos/Sample/ViewController.m +++ b/examples/Videos/Sample/ViewController.m @@ -49,22 +49,18 @@ ASVideoNode *hlsVideoNode = self.hlsVideoNode; [_rootNode addSubnode:hlsVideoNode]; - CGSize mainScreenBoundsSize = [UIScreen mainScreen].bounds.size; - _rootNode.layoutSpecBlock = ^ASLayoutSpec *(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) { - - // Layout all nodes absolute in a static layout spec - [guitarVideoNode setSizeWithCGSize:CGSizeMake(mainScreenBoundsSize.width, mainScreenBoundsSize.height / 3.0)]; guitarVideoNode.layoutPosition = CGPointMake(0, 0); + guitarVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/3); - [nicCageVideoNode setSizeWithCGSize:CGSizeMake(mainScreenBoundsSize.width/2, mainScreenBoundsSize.height / 3.0)]; - nicCageVideoNode.layoutPosition = CGPointMake(mainScreenBoundsSize.width / 2.0, mainScreenBoundsSize.height / 3.0); + nicCageVideoNode.layoutPosition = CGPointMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); + nicCageVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); - [simonVideoNode setSizeWithCGSize:CGSizeMake(mainScreenBoundsSize.width/2, mainScreenBoundsSize.height / 3.0)]; - simonVideoNode.layoutPosition = CGPointMake(0.0, mainScreenBoundsSize.height - (mainScreenBoundsSize.height / 3.0)); + simonVideoNode.layoutPosition = CGPointMake(0, [UIScreen mainScreen].bounds.size.height - ([UIScreen mainScreen].bounds.size.height/3)); + simonVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); - [hlsVideoNode setSizeWithCGSize:CGSizeMake(mainScreenBoundsSize.width / 2.0, mainScreenBoundsSize.height / 3.0)]; - hlsVideoNode.layoutPosition = CGPointMake(0.0, mainScreenBoundsSize.height / 3.0); + hlsVideoNode.layoutPosition = CGPointMake(0, [UIScreen mainScreen].bounds.size.height/3); + hlsVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[guitarVideoNode, nicCageVideoNode, simonVideoNode, hlsVideoNode]]; }; diff --git a/examples_extra/ASTraitCollection/Sample/KittenNode.m b/examples_extra/ASTraitCollection/Sample/KittenNode.m index 0a9dacbd..d6ac688b 100644 --- a/examples_extra/ASTraitCollection/Sample/KittenNode.m +++ b/examples_extra/ASTraitCollection/Sample/KittenNode.m @@ -77,7 +77,7 @@ static const CGFloat kInnerPadding = 10.0f; // kitten image, with a solid background colour serving as placeholder _imageNode = [[ASNetworkImageNode alloc] init]; _imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); - _imageNode.size = ASRelativeSizeRangeMakeWithExactCGSize(_kittenSize); + _imageNode.preferredFrameSize = _kittenSize; [_imageNode addTarget:self action:@selector(imageTapped:) forControlEvents:ASControlNodeEventTouchUpInside]; CGFloat scale = [UIScreen mainScreen].scale; diff --git a/examples_extra/BackgroundPropertySetting/Sample/DemoCellNode.swift b/examples_extra/BackgroundPropertySetting/Sample/DemoCellNode.swift index 1f4ae0e3..3fac84df 100644 --- a/examples_extra/BackgroundPropertySetting/Sample/DemoCellNode.swift +++ b/examples_extra/BackgroundPropertySetting/Sample/DemoCellNode.swift @@ -32,10 +32,10 @@ final class DemoCellNode: ASCellNode { override func layoutSpecThatFits(constrainedSize: ASSizeRange) -> ASLayoutSpec { let specA = ASRatioLayoutSpec(ratio: 1, child: childA) - specA.flexBasis = ASDimensionMakeWithPoints(1) + specA.flexBasis = ASRelativeDimensionMakeWithPoints(1) specA.flexGrow = true let specB = ASRatioLayoutSpec(ratio: 1, child: childB) - specB.flexBasis = ASDimensionMakeWithPoints(1) + specB.flexBasis = ASRelativeDimensionMakeWithPoints(1) specB.flexGrow = true let children = state.isReverse ? [ specB, specA ] : [ specA, specB ] let direction: ASStackLayoutDirection = state.isVertical ? .Vertical : .Horizontal diff --git a/examples_extra/SynchronousConcurrency/Sample/AsyncTableViewController.m b/examples_extra/SynchronousConcurrency/Sample/AsyncTableViewController.m index 3ab47084..328cbba5 100644 --- a/examples_extra/SynchronousConcurrency/Sample/AsyncTableViewController.m +++ b/examples_extra/SynchronousConcurrency/Sample/AsyncTableViewController.m @@ -30,12 +30,24 @@ @implementation AsyncTableViewController -#pragma mark - UIViewController. +#pragma mark - +#pragma mark UIViewController. - (instancetype)init { if (!(self = [super init])) return nil; + + _tableView = [[ASTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; + _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; + _tableView.asyncDataSource = self; + _tableView.asyncDelegate = self; + + ASRangeTuningParameters tuningParameters; + tuningParameters.leadingBufferScreenfuls = 0.5; + tuningParameters.trailingBufferScreenfuls = 1.0; + [_tableView setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypePreload]; + [_tableView setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeRender]; self.tabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemFeatured tag:0]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRedo @@ -54,30 +66,22 @@ { [super viewDidLoad]; - _tableView = [[ASTableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; - _tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; - _tableView.asyncDataSource = self; - _tableView.asyncDelegate = self; - - ASRangeTuningParameters tuningParameters; - tuningParameters.leadingBufferScreenfuls = 0.5; - tuningParameters.trailingBufferScreenfuls = 1.0; - [_tableView setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypePreload]; - [_tableView setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeRender]; - [self.view addSubview:_tableView]; } -#pragma mark - ASTableView. - -- (ASCellNodeBlock)tableView:(ASTableView *)tableView nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath +- (void)viewWillLayoutSubviews { - return ^{ - RandomCoreGraphicsNode *elementNode = [[RandomCoreGraphicsNode alloc] init]; - elementNode.size = ASRelativeSizeRangeMakeWithExactCGSize(CGSizeMake(320, 100)); - return elementNode; - }; + _tableView.frame = self.view.bounds; +} + +#pragma mark - +#pragma mark ASTableView. + +- (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath +{ + RandomCoreGraphicsNode *elementNode = [[RandomCoreGraphicsNode alloc] init]; + elementNode.preferredFrameSize = CGSizeMake(320, 100); + return elementNode; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section diff --git a/examples_extra/SynchronousConcurrency/Sample/RandomCoreGraphicsNode.m b/examples_extra/SynchronousConcurrency/Sample/RandomCoreGraphicsNode.m index d2afbd6e..f6a94959 100644 --- a/examples_extra/SynchronousConcurrency/Sample/RandomCoreGraphicsNode.m +++ b/examples_extra/SynchronousConcurrency/Sample/RandomCoreGraphicsNode.m @@ -92,8 +92,6 @@ - (void)layout { - [super layout]; - CGSize boundsSize = self.bounds.size; CGSize textSize = _textNode.calculatedSize; CGRect textRect = CGRectMake(roundf((boundsSize.width - textSize.width) / 2.0), diff --git a/examples_extra/SynchronousKittens/Sample/KittenNode.mm b/examples_extra/SynchronousKittens/Sample/KittenNode.mm index 8c8ba288..bf151fd8 100644 --- a/examples_extra/SynchronousKittens/Sample/KittenNode.mm +++ b/examples_extra/SynchronousKittens/Sample/KittenNode.mm @@ -140,9 +140,7 @@ static const CGFloat kInnerPadding = 10.0f; #if UseAutomaticLayout - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - CGSize imageSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) - : CGSizeMake(kImageSize, kImageSize); - _imageNode.size = ASRelativeSizeRangeMakeWithExactCGSize(imageSize); + _imageNode.preferredFrameSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); _textNode.flexShrink = YES; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; diff --git a/examples_extra/VideoTableView/Sample/NicCageNode.mm b/examples_extra/VideoTableView/Sample/NicCageNode.mm index 6e3d8ea4..cb680222 100644 --- a/examples_extra/VideoTableView/Sample/NicCageNode.mm +++ b/examples_extra/VideoTableView/Sample/NicCageNode.mm @@ -165,9 +165,7 @@ static const CGFloat kInnerPadding = 10.0f; #if UseAutomaticLayout - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - CGSize videoNodeSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) - : CGSizeMake(kImageSize, kImageSize); - _videoNode.size = ASRelativeSizeRangeMakeWithExactCGSize(videoNodeSize); + _videoNode.preferredFrameSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); _textNode.flexShrink = YES; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; diff --git a/smoke-tests/Life Without CocoaPods/Life Without CocoaPods/ViewController.m b/smoke-tests/Life Without CocoaPods/Life Without CocoaPods/ViewController.m index 05ac2445..761d164c 100644 --- a/smoke-tests/Life Without CocoaPods/Life Without CocoaPods/ViewController.m +++ b/smoke-tests/Life Without CocoaPods/Life Without CocoaPods/ViewController.m @@ -22,7 +22,7 @@ { self.textNode = [[ASTextNode alloc] init]; self.textNode.attributedText = [[NSAttributedString alloc] initWithString:@"Testing, testing." attributes:@{ NSForegroundColorAttributeName: [UIColor redColor] }]; - [self.textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, self.view.bounds.size)]; + [self.textNode measure:self.view.bounds.size]; self.textNode.frame = (CGRect){ .origin = CGPointZero, .size = self.textNode.calculatedSize }; [self.view addSubnode:self.textNode]; }