diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index d202ceed..b1878273 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -595,9 +595,27 @@ void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block) } else { // This is the root node. Trigger a full measurement pass on *current* thread. Old constrained size is re-used. [self measureWithSizeRange:oldConstrainedSize]; - CGRect bounds = self.bounds; - bounds.size = CGSizeMake(_layout.size.width, _layout.size.height); - self.bounds = bounds; + + CGSize oldSize = self.bounds.size; + CGSize newSize = _layout.size; + + if (! CGSizeEqualToSize(oldSize, newSize)) { + CGRect bounds = self.bounds; + bounds.size = newSize; + self.bounds = bounds; + + // Frame's origin must be preserved. Since it is computed from bounds size, anchorPoint + // and position (see frame setter in ASDisplayNode+UIViewBridge), position needs to be adjusted. + BOOL useLayer = (_layer && ASDisplayNodeThreadIsMain()); + CGPoint anchorPoint = (useLayer ? _layer.anchorPoint : self.anchorPoint); + CGPoint oldPosition = (useLayer ? _layer.position : self.position); + + CGFloat xDelta = (newSize.width - oldSize.width) * anchorPoint.x; + CGFloat yDelta = (newSize.height - oldSize.height) * anchorPoint.y; + CGPoint newPosition = CGPointMake(oldPosition.x + xDelta, oldPosition.y + yDelta); + + useLayer ? _layer.position = newPosition : self.position = newPosition; + } } } diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 6a9a3bd3..8948591d 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -791,7 +791,8 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) { } // Default size range - return ASSizeRangeMake(CGSizeZero, CGSizeMake(_maxWidthForNodesConstrainedSize, FLT_MAX)); + return ASSizeRangeMake(CGSizeMake(_maxWidthForNodesConstrainedSize, 0), + CGSizeMake(_maxWidthForNodesConstrainedSize, FLT_MAX)); } - (void)dataControllerLockDataSource diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm b/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm index 86551027..cbed7f2b 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm @@ -13,6 +13,7 @@ #import "ASAssert.h" #import "ASCollectionView.h" #import "CGRect+ASConvenience.h" +#import "UICollectionViewLayout+ASConvenience.h" struct ASDirectionalScreenfulBuffer { CGFloat positiveDirection; // Positive relative to iOS Core Animation layer coordinate space. @@ -56,7 +57,7 @@ typedef struct ASRangeGeometry ASRangeGeometry; @interface ASCollectionViewLayoutController () { - UIScrollView * __weak _scrollView; + ASCollectionView * __weak _collectionView; UICollectionViewLayout * __strong _collectionViewLayout; std::vector _updateRangeBoundsIndexedByRangeType; ASScrollDirection _scrollableDirections; @@ -72,7 +73,7 @@ typedef struct ASRangeGeometry ASRangeGeometry; } _scrollableDirections = [collectionView scrollableDirections]; - _scrollView = collectionView; + _collectionView = collectionView; _collectionViewLayout = [collectionView collectionViewLayout]; _updateRangeBoundsIndexedByRangeType = std::vector(ASLayoutRangeTypeCount); return self; @@ -94,8 +95,13 @@ typedef struct ASRangeGeometry ASRangeGeometry; - (ASRangeGeometry)rangeGeometryWithScrollDirection:(ASScrollDirection)scrollDirection rangeTuningParameters:(ASRangeTuningParameters)rangeTuningParameters { - CGRect rangeBounds = _scrollView.bounds; - CGRect updateBounds = _scrollView.bounds; + CGRect rangeBounds = _collectionView.bounds; + CGRect updateBounds = _collectionView.bounds; + + //scrollable directions can change for non-flow layouts + if ([_collectionViewLayout asdk_isFlowLayout] == NO) { + _scrollableDirections = [_collectionView scrollableDirections]; + } BOOL canScrollHorizontally = ASScrollDirectionContainsHorizontalDirection(_scrollableDirections); if (canScrollHorizontally) { @@ -148,7 +154,7 @@ typedef struct ASRangeGeometry ASRangeGeometry; return YES; } - CGRect currentBounds = _scrollView.bounds; + CGRect currentBounds = _collectionView.bounds; if (CGRectIsEmpty(currentBounds)) { currentBounds = CGRectMake(0, 0, viewportSize.width, viewportSize.height); } diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm index 8e97c9b4..e9f47c2e 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm @@ -24,6 +24,11 @@ return [[self alloc] initWithChildren:children]; } +- (instancetype)init +{ + return [self initWithChildren:@[]]; +} + - (instancetype)initWithChildren:(NSArray *)children { if (!(self = [super init])) { diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index d1f49351..2be42824 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -136,6 +136,7 @@ static const CGFloat kInnerPadding = 10.0f; { _imageNode.preferredFrameSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); _textNode.flexShrink = YES; + _textNode.flexGrow = YES; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; stackSpec.direction = ASStackLayoutDirectionHorizontal;