diff --git a/AsyncDisplayKit/ASCellNode.h b/AsyncDisplayKit/ASCellNode.h index 16fc60d1f3..78821ef2d8 100644 --- a/AsyncDisplayKit/ASCellNode.h +++ b/AsyncDisplayKit/ASCellNode.h @@ -19,8 +19,9 @@ typedef NSUInteger ASCellNodeAnimation; * The notification is done on main thread. * * @param node A node informing the delegate about the relayout. + * @param sizeChanged `YES` if the node's `calculatedSize` changed during the relayout, `NO` otherwise. */ -- (void)nodeDidRelayout:(ASCellNode *)node; +- (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged; @end /** diff --git a/AsyncDisplayKit/ASCellNode.m b/AsyncDisplayKit/ASCellNode.m index ef6652b700..50ad035702 100644 --- a/AsyncDisplayKit/ASCellNode.m +++ b/AsyncDisplayKit/ASCellNode.m @@ -53,11 +53,13 @@ - (void)setNeedsLayout { ASDisplayNodeAssertThreadAffinity(self); + CGSize oldSize = self.calculatedSize; [super setNeedsLayout]; - + if (_layoutDelegate != nil) { + BOOL sizeChanged = !CGSizeEqualToSize(oldSize, self.calculatedSize); ASPerformBlockOnMainThread(^{ - [_layoutDelegate nodeDidRelayout:self]; + [_layoutDelegate nodeDidRelayout:self sizeChanged:sizeChanged]; }); } } diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index d0ab712fa6..aac9507693 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -156,6 +156,7 @@ static BOOL _isInterceptedSelector(SEL sel) BOOL _asyncDelegateImplementsInsetSection; BOOL _collectionViewLayoutImplementsInsetSection; BOOL _asyncDataSourceImplementsConstrainedSizeForNode; + BOOL _queuedNodeSizeUpdate; ASBatchContext *_batchContext; @@ -911,10 +912,26 @@ static BOOL _isInterceptedSelector(SEL sel) #pragma mark - ASCellNodeDelegate -- (void)nodeDidRelayout:(ASCellNode *)node +- (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged { ASDisplayNodeAssertMainThread(); - // Cause UICollectionView to requery for the new height of this node + + if (!sizeChanged || _queuedNodeSizeUpdate) { + return; + } + + _queuedNodeSizeUpdate = YES; + [self performSelector:@selector(requeryNodeSizes) + withObject:nil + afterDelay:0 + inModes:@[ NSRunLoopCommonModes ]]; +} + +// Cause UICollectionView to requery for the new size of all nodes +- (void)requeryNodeSizes +{ + _queuedNodeSizeUpdate = NO; + [super performBatchUpdates:^{} completion:nil]; } diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 0a3dcf85b3..530a26f638 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -181,6 +181,7 @@ static BOOL _isInterceptedSelector(SEL sel) CGFloat _nodesConstrainedWidth; BOOL _ignoreNodesConstrainedWidthChange; + BOOL _queuedNodeHeightUpdate; } @property (atomic, assign) BOOL asyncDataSourceLocked; @@ -908,10 +909,26 @@ static BOOL _isInterceptedSelector(SEL sel) #pragma mark - ASCellNodeLayoutDelegate -- (void)nodeDidRelayout:(ASCellNode *)node +- (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged { ASDisplayNodeAssertMainThread(); - // Cause UITableView to requery for the new height of this node + + if (!sizeChanged || _queuedNodeHeightUpdate) { + return; + } + + _queuedNodeHeightUpdate = YES; + [self performSelector:@selector(requeryNodeHeights) + withObject:nil + afterDelay:0 + inModes:@[ NSRunLoopCommonModes ]]; +} + +// Cause UITableView to requery for the new height of this node +- (void)requeryNodeHeights +{ + _queuedNodeHeightUpdate = NO; + [super beginUpdates]; [super endUpdates]; }