diff --git a/AsyncDisplayKit/ASScrollNode.h b/AsyncDisplayKit/ASScrollNode.h index 9d1fd83071..5adbedf62d 100644 --- a/AsyncDisplayKit/ASScrollNode.h +++ b/AsyncDisplayKit/ASScrollNode.h @@ -9,6 +9,7 @@ // #import +#import NS_ASSUME_NONNULL_BEGIN @@ -33,6 +34,18 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign) BOOL automaticallyManagesContentSize; +/** + * @abstract This property controls how the constrainedSize is interpreted when sizing the content. + * if you are using automaticallyManagesContentSize, it can be crucial to ensure that the sizing is + * done how you expect. + * Vertical: The constrainedSize is interpreted as having unbounded .height (CGFLOAT_MAX), allowing + * stacks and other content in the layout spec to expand and result in scrollable content. + * Horizontal: The constrainedSize is interpreted as having unbounded .width (CGFLOAT_MAX), ... + * Vertical & Horizontal: the constrainedSize is interpreted as unbounded in both directions. + * @default ASScrollDirectionVerticalDirections + */ +@property (nonatomic, assign) ASScrollDirection scrollableDirections; + @end NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/ASScrollNode.mm b/AsyncDisplayKit/ASScrollNode.mm index f6050ee9e4..6e9afc69c7 100644 --- a/AsyncDisplayKit/ASScrollNode.mm +++ b/AsyncDisplayKit/ASScrollNode.mm @@ -56,6 +56,7 @@ @implementation ASScrollNode { + ASScrollDirection _scrollableDirections; BOOL _automaticallyManagesContentSize; CGSize _contentCalculatedSizeFromLayout; } @@ -70,12 +71,20 @@ restrictedToSize:(ASLayoutElementSize)size relativeToParentSize:(CGSize)parentSize { - ASLayout *layout = [super calculateLayoutThatFits:constrainedSize + ASDN::MutexLocker l(__instanceLock__); // Lock for using our instance variables. + + ASSizeRange contentConstrainedSize = constrainedSize; + if (ASScrollDirectionContainsVerticalDirection(_scrollableDirections)) { + contentConstrainedSize.max.height = CGFLOAT_MAX; + } + if (ASScrollDirectionContainsHorizontalDirection(_scrollableDirections)) { + contentConstrainedSize.max.width = CGFLOAT_MAX; + } + + ASLayout *layout = [super calculateLayoutThatFits:contentConstrainedSize restrictedToSize:size relativeToParentSize:parentSize]; - - ASDN::MutexLocker l(__instanceLock__); // Lock for using our two instance variables. - + if (_automaticallyManagesContentSize) { // To understand this code, imagine we're containing a horizontal stack set within a vertical table node. // Our parentSize is fixed ~375pt width, but 0 - INF height. Our stack measures 1000pt width, 50pt height. @@ -124,6 +133,25 @@ { ASDN::MutexLocker l(__instanceLock__); _automaticallyManagesContentSize = automaticallyManagesContentSize; + if (_automaticallyManagesContentSize == YES + && ASScrollDirectionContainsVerticalDirection(_scrollableDirections) == NO + && ASScrollDirectionContainsHorizontalDirection(_scrollableDirections) == NO) { + // Set the @default value, for more user-friendly behavior of the most + // common use cases of .automaticallyManagesContentSize. + _scrollableDirections = ASScrollDirectionVerticalDirections; + } +} + +- (ASScrollDirection)scrollableDirections +{ + ASDN::MutexLocker l(__instanceLock__); + return _scrollableDirections; +} + +- (void)setScrollableDirections:(ASScrollDirection)scrollableDirections +{ + ASDN::MutexLocker l(__instanceLock__); + _scrollableDirections = scrollableDirections; } @end