From f13f61c2f07105a153606fc17d61c7fdbb554743 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Wed, 7 Oct 2015 21:23:12 +0300 Subject: [PATCH 1/3] Add relayout item/row APIs to ASTableView and ASCollectionView. --- AsyncDisplayKit/ASCollectionView.h | 10 ++++++++++ AsyncDisplayKit/ASCollectionView.mm | 8 ++++++++ AsyncDisplayKit/ASDisplayNode.h | 10 +++++++--- AsyncDisplayKit/ASTableView.h | 12 ++++++++++++ AsyncDisplayKit/ASTableView.mm | 8 ++++++++ examples/Kittens/Sample/KittenNode.mm | 1 - examples/Kittens/Sample/ViewController.m | 3 +-- 7 files changed, 46 insertions(+), 6 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index d8f78c6e13..8b883d8e44 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -191,6 +191,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 4287e39075..9e0dac3ca3 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -406,6 +406,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 11a138ea4f..7234ccfc03 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 b7588f782b..f920d27c96 100644 --- a/AsyncDisplayKit/ASTableView.h +++ b/AsyncDisplayKit/ASTableView.h @@ -206,6 +206,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 6d83de9a95..d917b230b2 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -455,6 +455,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..542ee353b6 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -185,7 +185,6 @@ static const CGFloat kInnerPadding = 10.0f; - (void)toggleImageEnlargement { _isImageEnlarged = !_isImageEnlarged; - [self setNeedsLayout]; } - (void)toggleNodesSwap 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 From 91f3ba1f49f1a18cf34136faa9739d3f9830b71c Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Mon, 12 Oct 2015 21:34:44 +0300 Subject: [PATCH 2/3] Don't invalidateCalculatedLayout when ASTextCellNode's text is changed Because calling -invalidateCalculatedLayout removes the current constrained size and therefore any -setNeedsLayout calls in the future won't have a valid constrained size to proceed. Instead, cell nodes should be relaid-out using the new APIs introduced in ASTableView and ASCollectionView, which are -relayoutRowAtIndexPath:withRowAnimation and -relayoutItemAtIndexPath, respectively. --- AsyncDisplayKit/ASCellNode.m | 1 - 1 file changed, 1 deletion(-) 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 From 210a89e83cea3ce2613961c2e968389b28011f63 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Mon, 12 Oct 2015 22:24:19 +0300 Subject: [PATCH 3/3] Animate subnodes swap in Kitten example. --- examples/Kittens/Sample/KittenNode.mm | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index 542ee353b6..f6035e03be 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -190,7 +190,17 @@ static const CGFloat kInnerPadding = 10.0f; - (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