From dd29a890dfb1f614e65b255c35ce7bba863da1c2 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Sun, 28 Jun 2015 20:22:40 +0700 Subject: [PATCH] Still support -calculateLayoutThatFits: (and manual layout), for backward compatibility. --- AsyncDisplayKit.xcodeproj/project.pbxproj | 26 +++++----- .../{ASCellNode.mm => ASCellNode.m} | 6 +-- AsyncDisplayKit/ASDisplayNode+Subclasses.h | 52 ++++++++++++++++++- AsyncDisplayKit/ASDisplayNode.h | 20 +------ AsyncDisplayKit/ASDisplayNode.mm | 29 ++++++++++- AsyncDisplayKit/ASEditableTextNode.mm | 7 ++- AsyncDisplayKit/ASImageNode.mm | 8 +-- AsyncDisplayKit/ASTextNode.mm | 13 +++-- .../Private/ASDisplayNodeInternal.h | 9 ++-- .../ASLayoutNodeSnapshotTestsHelper.h | 1 + .../ASLayoutNodeSnapshotTestsHelper.m | 6 +-- examples/Kittens/Sample/BlurbNode.m | 6 +-- examples/Kittens/Sample/KittenNode.mm | 6 +-- 13 files changed, 121 insertions(+), 68 deletions(-) rename AsyncDisplayKit/{ASCellNode.mm => ASCellNode.m} (94%) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 9671ec06b6..5fab44e10b 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -186,10 +186,10 @@ AC3C4A511A1139C100143C57 /* ASCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; }; AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A501A1139C100143C57 /* ASCollectionView.mm */; }; AC3C4A541A113EEC00143C57 /* ASCollectionViewProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = AC3C4A531A113EEC00143C57 /* ASCollectionViewProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; }; - AC47D9421B3B891B00AAEE9D /* ASCellNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC6456071B0A335000CF11B8 /* ASCellNode.mm */; }; + AC47D9421B3B891B00AAEE9D /* ASCellNode.m in Sources */ = {isa = PBXBuildFile; fileRef = AC6456071B0A335000CF11B8 /* ASCellNode.m */; }; AC47D9451B3BB41900AAEE9D /* ASStaticLayoutNodeDimension.h in Headers */ = {isa = PBXBuildFile; fileRef = AC47D9431B3BB41900AAEE9D /* ASStaticLayoutNodeDimension.h */; settings = {ATTRIBUTES = (Public, ); }; }; AC47D9461B3BB41900AAEE9D /* ASStaticLayoutNodeDimension.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC47D9441B3BB41900AAEE9D /* ASStaticLayoutNodeDimension.mm */; }; - AC6456091B0A335000CF11B8 /* ASCellNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC6456071B0A335000CF11B8 /* ASCellNode.mm */; }; + AC6456091B0A335000CF11B8 /* ASCellNode.m in Sources */ = {isa = PBXBuildFile; fileRef = AC6456071B0A335000CF11B8 /* ASCellNode.m */; }; ACF6ED1A1B17843500DA7C62 /* ASBackgroundLayoutNode.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED011B17843500DA7C62 /* ASBackgroundLayoutNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; ACF6ED1B1B17843500DA7C62 /* ASBackgroundLayoutNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED021B17843500DA7C62 /* ASBackgroundLayoutNode.mm */; }; ACF6ED1C1B17843500DA7C62 /* ASCenterLayoutNode.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED031B17843500DA7C62 /* ASCenterLayoutNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -410,7 +410,7 @@ 058D09D6195D050800B7D73C /* ASControlNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASControlNode.m; sourceTree = ""; }; 058D09D7195D050800B7D73C /* ASControlNode+Subclasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASControlNode+Subclasses.h"; sourceTree = ""; }; 058D09D8195D050800B7D73C /* ASDisplayNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASDisplayNode.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 058D09D9195D050800B7D73C /* ASDisplayNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDisplayNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 058D09D9195D050800B7D73C /* ASDisplayNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDisplayNode.mm; sourceTree = ""; }; 058D09DA195D050800B7D73C /* ASDisplayNode+Subclasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "ASDisplayNode+Subclasses.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 058D09DB195D050800B7D73C /* ASDisplayNodeExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayNodeExtras.h; sourceTree = ""; }; 058D09DC195D050800B7D73C /* ASDisplayNodeExtras.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeExtras.mm; sourceTree = ""; }; @@ -524,24 +524,24 @@ AC3C4A531A113EEC00143C57 /* ASCollectionViewProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewProtocols.h; sourceTree = ""; }; AC47D9431B3BB41900AAEE9D /* ASStaticLayoutNodeDimension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutNodeDimension.h; path = AsyncDisplayKit/Layout/ASStaticLayoutNodeDimension.h; sourceTree = ""; }; AC47D9441B3BB41900AAEE9D /* ASStaticLayoutNodeDimension.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASStaticLayoutNodeDimension.mm; path = AsyncDisplayKit/Layout/ASStaticLayoutNodeDimension.mm; sourceTree = ""; }; - AC6456071B0A335000CF11B8 /* ASCellNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCellNode.mm; sourceTree = ""; }; + AC6456071B0A335000CF11B8 /* ASCellNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCellNode.m; sourceTree = ""; }; ACF6ED011B17843500DA7C62 /* ASBackgroundLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASBackgroundLayoutNode.h; path = AsyncDisplayKit/Layout/ASBackgroundLayoutNode.h; sourceTree = ""; }; - ACF6ED021B17843500DA7C62 /* ASBackgroundLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASBackgroundLayoutNode.mm; path = AsyncDisplayKit/Layout/ASBackgroundLayoutNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED021B17843500DA7C62 /* ASBackgroundLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASBackgroundLayoutNode.mm; path = AsyncDisplayKit/Layout/ASBackgroundLayoutNode.mm; sourceTree = ""; }; ACF6ED031B17843500DA7C62 /* ASCenterLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASCenterLayoutNode.h; path = AsyncDisplayKit/Layout/ASCenterLayoutNode.h; sourceTree = ""; }; - ACF6ED041B17843500DA7C62 /* ASCenterLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASCenterLayoutNode.mm; path = AsyncDisplayKit/Layout/ASCenterLayoutNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED041B17843500DA7C62 /* ASCenterLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASCenterLayoutNode.mm; path = AsyncDisplayKit/Layout/ASCenterLayoutNode.mm; sourceTree = ""; }; ACF6ED071B17843500DA7C62 /* ASDimension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASDimension.h; path = AsyncDisplayKit/Layout/ASDimension.h; sourceTree = ""; }; ACF6ED081B17843500DA7C62 /* ASDimension.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASDimension.mm; path = AsyncDisplayKit/Layout/ASDimension.mm; sourceTree = ""; }; ACF6ED091B17843500DA7C62 /* ASInsetLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASInsetLayoutNode.h; path = AsyncDisplayKit/Layout/ASInsetLayoutNode.h; sourceTree = ""; }; - ACF6ED0A1B17843500DA7C62 /* ASInsetLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASInsetLayoutNode.mm; path = AsyncDisplayKit/Layout/ASInsetLayoutNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED0A1B17843500DA7C62 /* ASInsetLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASInsetLayoutNode.mm; path = AsyncDisplayKit/Layout/ASInsetLayoutNode.mm; sourceTree = ""; }; ACF6ED0B1B17843500DA7C62 /* ASLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayout.h; path = AsyncDisplayKit/Layout/ASLayout.h; sourceTree = ""; }; ACF6ED0C1B17843500DA7C62 /* ASLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASLayout.mm; path = AsyncDisplayKit/Layout/ASLayout.mm; sourceTree = ""; }; ACF6ED0D1B17843500DA7C62 /* ASLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutNode.h; path = AsyncDisplayKit/Layout/ASLayoutNode.h; sourceTree = ""; }; - ACF6ED0E1B17843500DA7C62 /* ASLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASLayoutNode.mm; path = AsyncDisplayKit/Layout/ASLayoutNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED0E1B17843500DA7C62 /* ASLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASLayoutNode.mm; path = AsyncDisplayKit/Layout/ASLayoutNode.mm; sourceTree = ""; }; ACF6ED111B17843500DA7C62 /* ASLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutable.h; path = AsyncDisplayKit/Layout/ASLayoutable.h; sourceTree = ""; }; ACF6ED121B17843500DA7C62 /* ASOverlayLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASOverlayLayoutNode.h; path = AsyncDisplayKit/Layout/ASOverlayLayoutNode.h; sourceTree = ""; }; - ACF6ED131B17843500DA7C62 /* ASOverlayLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASOverlayLayoutNode.mm; path = AsyncDisplayKit/Layout/ASOverlayLayoutNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED131B17843500DA7C62 /* ASOverlayLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASOverlayLayoutNode.mm; path = AsyncDisplayKit/Layout/ASOverlayLayoutNode.mm; sourceTree = ""; }; ACF6ED141B17843500DA7C62 /* ASRatioLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRatioLayoutNode.h; path = AsyncDisplayKit/Layout/ASRatioLayoutNode.h; sourceTree = ""; }; - ACF6ED151B17843500DA7C62 /* ASRatioLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASRatioLayoutNode.mm; path = AsyncDisplayKit/Layout/ASRatioLayoutNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED151B17843500DA7C62 /* ASRatioLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASRatioLayoutNode.mm; path = AsyncDisplayKit/Layout/ASRatioLayoutNode.mm; sourceTree = ""; }; ACF6ED161B17843500DA7C62 /* ASStackLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutNode.h; path = AsyncDisplayKit/Layout/ASStackLayoutNode.h; sourceTree = ""; }; ACF6ED171B17843500DA7C62 /* ASStackLayoutNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASStackLayoutNode.mm; path = AsyncDisplayKit/Layout/ASStackLayoutNode.mm; sourceTree = ""; }; ACF6ED181B17843500DA7C62 /* ASStaticLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutNode.h; path = AsyncDisplayKit/Layout/ASStaticLayoutNode.h; sourceTree = ""; }; @@ -678,7 +678,7 @@ isa = PBXGroup; children = ( 055F1A3A19ABD43F004DAFF1 /* ASCellNode.h */, - AC6456071B0A335000CF11B8 /* ASCellNode.mm */, + AC6456071B0A335000CF11B8 /* ASCellNode.m */, AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */, AC3C4A501A1139C100143C57 /* ASCollectionView.mm */, AC3C4A531A113EEC00143C57 /* ASCollectionViewProtocols.h */, @@ -1392,7 +1392,7 @@ 205F0E101B371875007741D0 /* UICollectionViewLayout+ASConvenience.m in Sources */, 05A6D05B19D0EB64002DD95E /* ASDealloc2MainObject.m in Sources */, 058D0A17195D050800B7D73C /* ASTextNode.mm in Sources */, - AC6456091B0A335000CF11B8 /* ASCellNode.mm in Sources */, + AC6456091B0A335000CF11B8 /* ASCellNode.m in Sources */, ACF6ED231B17843500DA7C62 /* ASInsetLayoutNode.mm in Sources */, 058D0A27195D050800B7D73C /* _ASPendingState.m in Sources */, 0516FA411A1563D200B4EBED /* ASMultiplexImageNode.mm in Sources */, @@ -1465,7 +1465,7 @@ B350621E1B010EFD0018CF92 /* ASHighlightOverlayLayer.mm in Sources */, B35062271B010EFD0018CF92 /* ASRangeController.mm in Sources */, B35061F91B010EFD0018CF92 /* ASControlNode.m in Sources */, - AC47D9421B3B891B00AAEE9D /* ASCellNode.mm in Sources */, + AC47D9421B3B891B00AAEE9D /* ASCellNode.m in Sources */, 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */, B35062561B010EFD0018CF92 /* ASSentinel.m in Sources */, B350624A1B010EFD0018CF92 /* _ASCoreAnimationExtras.mm in Sources */, diff --git a/AsyncDisplayKit/ASCellNode.mm b/AsyncDisplayKit/ASCellNode.m similarity index 94% rename from AsyncDisplayKit/ASCellNode.mm rename to AsyncDisplayKit/ASCellNode.m index 3869b99756..3b548ea583 100644 --- a/AsyncDisplayKit/ASCellNode.mm +++ b/AsyncDisplayKit/ASCellNode.m @@ -105,12 +105,12 @@ static const CGFloat kFontSize = 18.0f; return self; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize{ +- (id)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ static const CGFloat kHorizontalPadding = 15.0f; static const CGFloat kVerticalPadding = 11.0f; UIEdgeInsets insets = UIEdgeInsetsMake(kVerticalPadding, kHorizontalPadding, kVerticalPadding, kHorizontalPadding); - id layout = [ASInsetLayoutNode newWithInsets:insets child:_textNode]; - return [layout calculateLayoutThatFits:constrainedSize]; + return [ASInsetLayoutNode newWithInsets:insets child:_textNode]; } - (void)setText:(NSString *)text diff --git a/AsyncDisplayKit/ASDisplayNode+Subclasses.h b/AsyncDisplayKit/ASDisplayNode+Subclasses.h index 214772d12d..b5e14c95d2 100644 --- a/AsyncDisplayKit/ASDisplayNode+Subclasses.h +++ b/AsyncDisplayKit/ASDisplayNode+Subclasses.h @@ -14,6 +14,7 @@ #import #import +#import /** * The subclass header _ASDisplayNode+Subclasses_ defines the following methods that either must or can be overriden by @@ -35,7 +36,7 @@ * variables. */ -@interface ASDisplayNode (Subclassing) +@interface ASDisplayNode (Subclassing) /** @name View Configuration */ @@ -107,6 +108,55 @@ */ - (void)layoutDidFinish; + +/** @name Layout calculation */ + + +/** + * @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 This method is called on a non-main thread. The default implementation calls either -layoutSpecThatFits: + * or -calculateSizeThatFits:, whichever method is available. Thus, subclasses rarely need to override this method, + * override -layoutSpecThatFits: or -calculateSizeThatFits: instead. + * + * @note This method should not be called directly outside of ASDisplayNode; use -measure: or -calculatedLayout instead. + */ +- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize; + +/** + * @abstract Return the calculated size. + * + * @param constrainedSize The maximum size the receiver should fit in. + * + * @discussion Subclasses that override should expect this method to be called on a non-main thread. The returned size + * is wrapped in an ASLayout and cached by ASDisplayNode for quick access during -layout. Other expensive work that needs to + * be done before display can be performed here, and using ivars to cache any valuable intermediate results is + * encouraged. + * + * @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 -measure: or -calculatedLayout instead. + */ +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize; + +/** + * @abstract Return a layout spec that describes the layout of the receiver and its children. + * + * @param constrainedSize The minimum and maximum sizes the receiver should fit in. + * + * @discussion Subclasses that override should expect this method to be called on a non-main thread. The returned layout spec + * is used to calculate an ASLayout and cached by ASDisplayNode for quick access during -layout. Other expensive work that needs to + * be done before display can be performed here, and using ivars to cache any valuable intermediate results is + * encouraged. + * + * @note This method should not be called directly outside of ASDisplayNode; use -measure: or -calculatedLayout instead. + */ +- (id)layoutSpecThatFits:(ASSizeRange)constrainedSize; + /** * @abstract Invalidate previously measured and cached layout. * diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index a9387ada08..3d0c1290cc 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -11,8 +11,6 @@ #import #import #import -#import - typedef UIView *(^ASDisplayNodeViewBlock)(); typedef CALayer *(^ASDisplayNodeLayerBlock)(); @@ -33,7 +31,7 @@ typedef CALayer *(^ASDisplayNodeLayerBlock)(); * */ -@interface ASDisplayNode : ASDealloc2MainObject +@interface ASDisplayNode : ASDealloc2MainObject /** @name Initializing a node object */ @@ -155,22 +153,6 @@ typedef CALayer *(^ASDisplayNodeLayerBlock)(); */ @property (nonatomic, readonly, assign) CGSize constrainedSizeForCalculatedLayout; -/** - * @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. - * - * @discussion Subclasses that override should expect this method to be called on a non-main thread. The returned layout - * is cached by ASDisplayNode for quick access during -layout, via -calculatedSize. Other expensive work that needs to - * be done before display can be performed here, and using ivars to cache any valuable intermediate results is - * encouraged. - * - * @note This method should not be called directly outside of ASDisplayNode; use -measure: or -calculatedLayout instead. - */ -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize; - /** @name Managing the nodes hierarchy */ diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 59a1dd5c6f..a46a54fc7a 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -76,6 +76,12 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)()) ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measure:)), @"Subclass %@ must not override measure 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)); + + // At most one of the three layout methods is overridden + ASDisplayNodeAssert((ASDisplayNodeSubclassOverridesSelector(self, @selector(calculateSizeThatFits:)) ? 1 : 0) + + (ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutSpecThatFits:)) ? 1 : 0) + + (ASDisplayNodeSubclassOverridesSelector(self, @selector(calculateLayoutThatFits:)) ? 1 : 0) <= 1, + @"Subclass %@ must override at most one of the three layout methods: calculateLayoutThatFits, layoutSpecThatFits or calculateSizeThatFits", NSStringFromClass(self)); } + (BOOL)layerBackedNodesEnabled @@ -122,6 +128,9 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)()) if (ASDisplayNodeSubclassOverridesSelector([self class], @selector(touchesEnded:withEvent:))) { overrides |= ASDisplayNodeMethodOverrideTouchesEnded; } + if (ASDisplayNodeSubclassOverridesSelector([self class], @selector(calculateSizeThatFits:))) { + overrides |= ASDisplayNodeMethodOverrideCalculateSizeThatFits; + } _methodOverrides = overrides; _flexBasis = ASRelativeDimensionUnconstrained; @@ -1271,7 +1280,25 @@ static NSInteger incrementIfFound(NSInteger i) { - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize { ASDisplayNodeAssertThreadAffinity(self); - return [ASLayout newWithLayoutableObject:self size:constrainedSize.min]; + if (_methodOverrides & ASDisplayNodeMethodOverrideCalculateSizeThatFits) { + CGSize size = [self calculateSizeThatFits:constrainedSize.max]; + return [ASLayout newWithLayoutableObject:self size:ASSizeRangeClamp(constrainedSize, size)]; + } else { + id layoutSpec = [self layoutSpecThatFits:constrainedSize]; + return [layoutSpec calculateLayoutThatFits:constrainedSize]; + } +} + +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize +{ + ASDisplayNodeAssertThreadAffinity(self); + return CGSizeZero; +} + +- (id)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ + ASDisplayNodeAssertThreadAffinity(self); + return nil; } - (ASLayout *)calculatedLayout diff --git a/AsyncDisplayKit/ASEditableTextNode.mm b/AsyncDisplayKit/ASEditableTextNode.mm index 46d9479dd8..e2aea6b744 100644 --- a/AsyncDisplayKit/ASEditableTextNode.mm +++ b/AsyncDisplayKit/ASEditableTextNode.mm @@ -145,12 +145,11 @@ [self.view addSubview:_textKitComponents.textView]; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { ASTextKitComponents *displayedComponents = [self isDisplayingPlaceholder] ? _placeholderTextKitComponents : _textKitComponents; - CGSize textSize = [displayedComponents sizeForConstrainedWidth:constrainedSize.max.width]; - CGSize finalSize = CGSizeMake(constrainedSize.max.width, fminf(textSize.height, constrainedSize.max.height)); - return [ASLayout newWithLayoutableObject:self size:finalSize]; + CGSize textSize = [displayedComponents sizeForConstrainedWidth:constrainedSize.width]; + return CGSizeMake(constrainedSize.width, fminf(textSize.height, constrainedSize.height)); } - (void)layout diff --git a/AsyncDisplayKit/ASImageNode.mm b/AsyncDisplayKit/ASImageNode.mm index 6768b23a8f..d7cdebbd94 100644 --- a/AsyncDisplayKit/ASImageNode.mm +++ b/AsyncDisplayKit/ASImageNode.mm @@ -108,13 +108,13 @@ return nil; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { ASDN::MutexLocker l(_imageLock); - CGSize size = CGSizeZero; if (_image) - size = _image.size; - return [ASLayout newWithLayoutableObject:self size:ASSizeRangeClamp(constrainedSize, size)]; + return _image.size; + else + return CGSizeZero; } - (void)setImage:(UIImage *)image diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index e4b7d5f5bd..431bf38ccd 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -186,10 +186,10 @@ ASDISPLAYNODE_INLINE CGFloat ceilPixelValue(CGFloat f) #pragma mark - ASDisplayNode -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { - ASDisplayNodeAssert(constrainedSize.max.width >= 0, @"Constrained width for text (%f) is too narrow", constrainedSize.max.width); - ASDisplayNodeAssert(constrainedSize.max.height >= 0, @"Constrained height for text (%f) is too short", constrainedSize.max.height); + ASDisplayNodeAssert(constrainedSize.width >= 0, @"Constrained width for text (%f) is too narrow", constrainedSize.width); + ASDisplayNodeAssert(constrainedSize.height >= 0, @"Constrained height for text (%f) is too short", constrainedSize.height); // The supplied constrainedSize should include room for shadowPadding. // Inset the constrainedSize by the shadow padding to get the size available for text. UIEdgeInsets shadowPadding = [[self _shadower] shadowPadding]; @@ -197,7 +197,7 @@ ASDISPLAYNODE_INLINE CGFloat ceilPixelValue(CGFloat f) UIEdgeInsets shadowPaddingOutset = ASDNEdgeInsetsInvert(shadowPadding); // Inset the padded constrainedSize to get the remaining size available for text - CGRect constrainedRect = CGRect{CGPointZero, constrainedSize.max}; + CGRect constrainedRect = CGRect{CGPointZero, constrainedSize}; CGSize constrainedSizeForText = UIEdgeInsetsInsetRect(constrainedRect, shadowPaddingOutset).size; ASDisplayNodeAssert(constrainedSizeForText.width >= 0, @"Constrained width for text (%f) after subtracting shadow padding (%@) is too narrow", constrainedSizeForText.width, NSStringFromUIEdgeInsets(shadowPadding)); ASDisplayNodeAssert(constrainedSizeForText.height >= 0, @"Constrained height for text (%f) after subtracting shadow padding (%@) is too short", constrainedSizeForText.height, NSStringFromUIEdgeInsets(shadowPadding)); @@ -212,9 +212,8 @@ ASDISPLAYNODE_INLINE CGFloat ceilPixelValue(CGFloat f) ASDisplayNodeAssert(renderSizePlusShadowPadding.width >= 0, @"Calculated width for text with shadow padding (%f) is too narrow", constrainedSizeForText.width); ASDisplayNodeAssert(renderSizePlusShadowPadding.height >= 0, @"Calculated height for text with shadow padding (%f) is too short", constrainedSizeForText.height); - CGSize finalSize = CGSizeMake(MIN(ceilPixelValue(renderSizePlusShadowPadding.width), constrainedSize.max.width), - MIN(ceilPixelValue(renderSizePlusShadowPadding.height), constrainedSize.max.height)); - return [ASLayout newWithLayoutableObject:self size:finalSize]; + return CGSizeMake(MIN(ceilPixelValue(renderSizePlusShadowPadding.width), constrainedSize.width), + MIN(ceilPixelValue(renderSizePlusShadowPadding.height), constrainedSize.height)); } - (void)displayDidFinish diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index a826fa3b40..331bc4e9ed 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -24,10 +24,11 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)()); typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) { ASDisplayNodeMethodOverrideNone = 0, - ASDisplayNodeMethodOverrideTouchesBegan = 1 << 0, - ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1, - ASDisplayNodeMethodOverrideTouchesEnded = 1 << 2, - ASDisplayNodeMethodOverrideTouchesMoved = 1 << 3 + ASDisplayNodeMethodOverrideTouchesBegan = 1 << 0, + ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1, + ASDisplayNodeMethodOverrideTouchesEnded = 1 << 2, + ASDisplayNodeMethodOverrideTouchesMoved = 1 << 3, + ASDisplayNodeMethodOverrideCalculateSizeThatFits = 1 << 4 }; @class _ASPendingState; diff --git a/AsyncDisplayKitTests/ASLayoutNodeSnapshotTestsHelper.h b/AsyncDisplayKitTests/ASLayoutNodeSnapshotTestsHelper.h index 4dac9133b8..b27ab5939f 100644 --- a/AsyncDisplayKitTests/ASLayoutNodeSnapshotTestsHelper.h +++ b/AsyncDisplayKitTests/ASLayoutNodeSnapshotTestsHelper.h @@ -7,6 +7,7 @@ // #import "ASSnapshotTestCase.h" +#import "ASDisplayNode+Subclasses.h" @class ASLayoutNode; diff --git a/AsyncDisplayKitTests/ASLayoutNodeSnapshotTestsHelper.m b/AsyncDisplayKitTests/ASLayoutNodeSnapshotTestsHelper.m index 0b03d1e549..22c44dbec9 100644 --- a/AsyncDisplayKitTests/ASLayoutNodeSnapshotTestsHelper.m +++ b/AsyncDisplayKitTests/ASLayoutNodeSnapshotTestsHelper.m @@ -64,11 +64,9 @@ @implementation ASStaticSizeDisplayNode -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { - return CGSizeEqualToSize(_staticSize, CGSizeZero) - ? [super calculateLayoutThatFits:constrainedSize] - : [ASLayout newWithLayoutableObject:self size:ASSizeRangeClamp(constrainedSize, _staticSize)]; + return _staticSize; } @end diff --git a/examples/Kittens/Sample/BlurbNode.m b/examples/Kittens/Sample/BlurbNode.m index 78b8c192c5..3206bf64e0 100644 --- a/examples/Kittens/Sample/BlurbNode.m +++ b/examples/Kittens/Sample/BlurbNode.m @@ -71,12 +71,10 @@ static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName"; [super didLoad]; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (id)layoutSpecThatFits:(ASSizeRange)constrainedSize { - // called on a background thread. custom nodes must call -measure: on their subnodes in -calculateSizeThatFits: UIEdgeInsets insets = UIEdgeInsetsMake(kTextPadding, kTextPadding, kTextPadding, kTextPadding); - id layoutSpec = [ASInsetLayoutNode newWithInsets:insets child:_textNode]; - return [layoutSpec calculateLayoutThatFits:constrainedSize]; + return [ASInsetLayoutNode newWithInsets:insets child:_textNode]; } #pragma mark - diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index b10284df93..1c509a5b19 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -127,14 +127,14 @@ static const CGFloat kInnerPadding = 10.0f; NSParagraphStyleAttributeName: style }; } -- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +- (id)layoutSpecThatFits:(ASSizeRange)constrainedSize { ASRatioLayoutNode *imagePlaceholder = [ASRatioLayoutNode newWithRatio:1.0 child:_imageNode]; imagePlaceholder.flexBasis = ASRelativeDimensionMakeWithPoints(kImageSize); _textNode.flexShrink = YES; - id layoutSpec = + return [ASInsetLayoutNode newWithInsets:UIEdgeInsetsMake(kOuterPadding, kOuterPadding, kOuterPadding, kOuterPadding) child: @@ -144,8 +144,6 @@ static const CGFloat kInnerPadding = 10.0f; .spacing = kInnerPadding } children:@[imagePlaceholder, _textNode]]]; - - return [layoutSpec calculateLayoutThatFits:constrainedSize]; } - (void)layout