diff --git a/AsyncDisplayKit/ASCellNode.h b/AsyncDisplayKit/ASCellNode.h index ccd62a317e..6c3e5001cc 100644 --- a/AsyncDisplayKit/ASCellNode.h +++ b/AsyncDisplayKit/ASCellNode.h @@ -14,6 +14,24 @@ NS_ASSUME_NONNULL_BEGIN typedef NSUInteger ASCellNodeAnimation; +typedef enum : NSUInteger { + /** + * Indicates a cell has just became visible + */ + ASCellNodeVisibilityEventVisible, + /** + * Its position (determined by scrollView.contentOffset) has changed while at least 1px remains visible. + * It is possible that 100% of the cell is visible both before and after and only its position has changed, + * or that the position change has resulted in more or less of the cell being visible. + * Use CGRectIntersect between cellFrame and scrollView.bounds to get this rectangle + */ + ASCellNodeVisibilityEventVisibleRectChanged, + /** + * Indicates a cell is no longer visible + */ + ASCellNodeVisibilityEventInvisible, +} ASCellNodeVisibilityEvent; + /** * Generic cell node. Subclass this instead of `ASDisplayNode` to use with `ASTableView` and `ASCollectionView`. */ @@ -90,7 +108,7 @@ typedef NSUInteger ASCellNodeAnimation; */ - (instancetype)initWithViewControllerBlock:(ASDisplayNodeViewControllerBlock)viewControllerBlock didLoadBlock:(nullable ASDisplayNodeDidLoadBlock)didLoadBlock; -- (void)visibleNodeDidScroll:(UIScrollView *)scrollView withCellFrame:(CGRect)cellFrame; +- (void)cellNodeVisibilityEvent:(ASCellNodeVisibilityEvent)event inScrollView:(UIScrollView *)scrollView withCellFrame:(CGRect)cellFrame; @end diff --git a/AsyncDisplayKit/ASCellNode.m b/AsyncDisplayKit/ASCellNode.m index 0d528cff6f..88c64b32ad 100644 --- a/AsyncDisplayKit/ASCellNode.m +++ b/AsyncDisplayKit/ASCellNode.m @@ -179,7 +179,9 @@ [(_ASDisplayView *)self.view __forwardTouchesCancelled:touches withEvent:event]; } -- (void)visibleNodeDidScroll:(UIScrollView *)scrollView withCellFrame:(CGRect)cellFrame +- (void)cellNodeVisibilityEvent:(ASCellNodeVisibilityEvent)event + inScrollView:(UIScrollView *)scrollView + withCellFrame:(CGRect)cellFrame { // To be overriden by subclasses } diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 26a404fc83..69d5e75da0 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -542,8 +542,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; if (cellNode.neverShowPlaceholders) { [cellNode recursivelyEnsureDisplaySynchronously:YES]; } - if (ASSubclassOverridesSelector([ASCellNode class], [cellNode class], @selector(visibleNodeDidScroll:withCellFrame:))) { + if (ASSubclassOverridesSelector([ASCellNode class], [cellNode class], @selector(cellNodeVisibilityEvent:inScrollView:withCellFrame:))) { [_cellsForVisibilityUpdates addObject:cell]; + [cellNode cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisible + inScrollView:collectionView + withCellFrame:cell.frame]; } } @@ -556,8 +559,14 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; ASDisplayNodeAssertNotNil(node, @"Expected node associated with removed cell not to be nil."); [_asyncDelegate collectionView:self didEndDisplayingNode:node forItemAtIndexPath:indexPath]; } - [_cellsForVisibilityUpdates removeObject:cell]; - + + if ([_cellsForVisibilityUpdates containsObject:cell]) { + ASCellNode *node = ((_ASCollectionViewCell *)cell).node; + [node cellNodeVisibilityEvent:ASCellNodeVisibilityEventInvisible + inScrollView:collectionView + withCellFrame:cell.frame]; + [_cellsForVisibilityUpdates removeObject:cell]; + } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -681,9 +690,10 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)scrollViewDidScroll:(UIScrollView *)scrollView { for (_ASCollectionViewCell *collectionCell in _cellsForVisibilityUpdates) { - ASCellNode *node = [collectionCell node]; // Only nodes that respond to the selector are added to _cellsForVisibilityUpdates - [node visibleNodeDidScroll:scrollView withCellFrame:collectionCell.frame]; + [[collectionCell node] cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisibleRectChanged + inScrollView:scrollView + withCellFrame:collectionCell.frame]; } if (_asyncDelegateImplementsScrollviewDidScroll) { [_asyncDelegate scrollViewDidScroll:scrollView]; diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 947b40774e..cc1c6cf686 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -597,8 +597,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)scrollViewDidScroll:(UIScrollView *)scrollView { for (_ASTableViewCell *tableCell in _cellsForVisibilityUpdates) { - ASCellNode *node = [tableCell node]; - [node visibleNodeDidScroll:scrollView withCellFrame:tableCell.frame]; + [[tableCell node] cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisibleRectChanged + inScrollView:scrollView + withCellFrame:tableCell.frame]; } if (_asyncDelegateImplementsScrollviewDidScroll) { [_asyncDelegate scrollViewDidScroll:scrollView]; @@ -617,8 +618,11 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; ASCellNode *cellNode = [cell node]; - if (ASSubclassOverridesSelector([ASCellNode class], [cellNode class], @selector(visibleNodeDidScroll:withCellFrame:))) { + if (ASSubclassOverridesSelector([ASCellNode class], [cellNode class], @selector(cellNodeVisibilityEvent:inScrollView:withCellFrame:))) { [_cellsForVisibilityUpdates addObject:cell]; + [cellNode cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisible + inScrollView:tableView + withCellFrame:cell.frame]; } if (cellNode.neverShowPlaceholders) { [cellNode recursivelyEnsureDisplaySynchronously:YES]; @@ -639,7 +643,13 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; [_asyncDelegate tableView:self didEndDisplayingNode:node forRowAtIndexPath:indexPath]; } - [_cellsForVisibilityUpdates removeObject:cell]; + if ([_cellsForVisibilityUpdates containsObject:cell]) { + [_cellsForVisibilityUpdates removeObject:cell]; + ASCellNode *node = ((_ASTableViewCell *)cell).node; + [node cellNodeVisibilityEvent:ASCellNodeVisibilityEventInvisible + inScrollView:tableView + withCellFrame:cell.frame]; + } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations"