diff --git a/AsyncDisplayKit/ASCellNode.m b/AsyncDisplayKit/ASCellNode.m index 80bc34598c..ae6b3f6761 100644 --- a/AsyncDisplayKit/ASCellNode.m +++ b/AsyncDisplayKit/ASCellNode.m @@ -123,7 +123,6 @@ static const CGFloat kFontSize = 18.0f; _textNode.attributedString = [[NSAttributedString alloc] initWithString:_text attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kFontSize]}]; - [self invalidateCalculatedLayout]; } @end diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index eca5ba4883..4cea634226 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -223,6 +223,16 @@ */ - (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths; +/** + * Relayouts the specified item. + * + * @param indexPath The index path identifying the item to relayout. + * + * @discussion This method must be called from the main thread. The relayout is excuted on main thread. + * The node of the specified item must be updated to cause layout changes before this method is called. + */ +- (void)relayoutItemAtIndexPath:(NSIndexPath *)indexPath; + /** * Moves the item at a specified location to a destination location. * diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 2ba19a5e05..c123914ab7 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -458,6 +458,14 @@ static BOOL _isInterceptedSelector(SEL sel) [_dataController reloadRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone]; } +- (void)relayoutItemAtIndexPath:(NSIndexPath *)indexPath +{ + ASDisplayNodeAssertMainThread(); + ASCellNode *node = [self nodeForItemAtIndexPath:indexPath]; + [node setNeedsLayout]; + [super reloadItemsAtIndexPaths:@[indexPath]]; +} + - (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath { ASDisplayNodeAssertMainThread(); diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index bb84512f43..45721a5d06 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -556,9 +556,13 @@ typedef void (^ASDisplayNodeDidLoadBlock)(ASDisplayNode *node); * If this node was measured, calling this method triggers an internal relayout: the calculated layout is invalidated, * and the supernode is notified or (if this node is the root one) a full measurement pass is executed using the old constrained size. * - * Note: If the relayout causes a change in size of the root node that is attached to a container view - * (table or collection view, for example), the container view must be notified to relayout. - * For ASTableView and ASCollectionView, an empty batch editing transaction must be triggered to animate to new row / item sizes. + * Note: If the relayout causes a change in size of the root node that is attached to a container view, + * the container view must be notified to relayout. + * For ASTableView and ASCollectionView, instead of calling this method directly, + * it is recommended to call -relayoutRowAtIndexPath:withRowAnimation and -relayoutItemAtIndexPath: respectively. + * + * @see [ASTableView relayoutRowAtIndexPath:withRowAnimation:] + * @see [ASCollectionView relayoutItemAtIndexPath:] */ - (void)setNeedsLayout; diff --git a/AsyncDisplayKit/ASTableView.h b/AsyncDisplayKit/ASTableView.h index d7ea79dc2d..98753ca9a6 100644 --- a/AsyncDisplayKit/ASTableView.h +++ b/AsyncDisplayKit/ASTableView.h @@ -214,6 +214,18 @@ */ - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation; +/** + * Relayouts the specified row using a given animation effect. + * + * @param indexPath The index path identifying the row to relayout. + * + * @param animation A constant that indicates how the relayout is to be animated. See UITableViewRowAnimation. + * + * @discussion This method must be called from the main thread. The relayout is excuted on main thread. + * The node of the specified row must be updated to cause layout changes before this method is called. + */ +- (void)relayoutRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation; + /** * Moves the row at a specified location to a destination location. * diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 18695a714b..56a5e41b82 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -466,6 +466,14 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) { [_dataController reloadRowsAtIndexPaths:indexPaths withAnimationOptions:animation]; } +- (void)relayoutRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation +{ + ASDisplayNodeAssertMainThread(); + ASCellNode *node = [self nodeForRowAtIndexPath:indexPath]; + [node setNeedsLayout]; + [super reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:animation]; +} + - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath { ASDisplayNodeAssertMainThread(); diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index 847a2629c7..f6035e03be 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -185,13 +185,22 @@ static const CGFloat kInnerPadding = 10.0f; - (void)toggleImageEnlargement { _isImageEnlarged = !_isImageEnlarged; - [self setNeedsLayout]; } - (void)toggleNodesSwap { _swappedTextAndImage = !_swappedTextAndImage; - [self setNeedsLayout]; + + [UIView animateWithDuration:0.15 animations:^{ + self.alpha = 0; + } completion:^(BOOL finished) { + [self setNeedsLayout]; + [self.view layoutIfNeeded]; + + [UIView animateWithDuration:0.15 animations:^{ + self.alpha = 1; + }]; + }]; } @end diff --git a/examples/Kittens/Sample/ViewController.m b/examples/Kittens/Sample/ViewController.m index 7989fe15ce..41630435aa 100644 --- a/examples/Kittens/Sample/ViewController.m +++ b/examples/Kittens/Sample/ViewController.m @@ -118,11 +118,10 @@ static const NSInteger kMaxLitterSize = 100; // max number of kitten cell - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [_tableView deselectRowAtIndexPath:indexPath animated:YES]; - [_tableView beginUpdates]; // Assume only kitten nodes are selectable (see -tableView:shouldHighlightRowAtIndexPath:). KittenNode *node = (KittenNode *)[_tableView nodeForRowAtIndexPath:indexPath]; [node toggleImageEnlargement]; - [_tableView endUpdates]; + [_tableView relayoutRowAtIndexPath:indexPath withRowAnimation:UITableViewRowAnimationAutomatic]; } - (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath