diff --git a/AsyncDisplayKit/ASTableView.h b/AsyncDisplayKit/ASTableView.h index 7d36cc3d4d..06ce862606 100644 --- a/AsyncDisplayKit/ASTableView.h +++ b/AsyncDisplayKit/ASTableView.h @@ -433,6 +433,18 @@ NS_ASSUME_NONNULL_BEGIN */ - (BOOL)shouldBatchFetchForTableView:(ASTableView *)tableView; +/** + * Provides the constrained size range for measuring the row at the index path. + * Note: the widths in the returned size range are ignored! + * + * @param tableView The sender. + * + * @param indexPath The index path of the node. + * + * @returns A constrained size range for layout the node at this index path. + */ +- (ASSizeRange)tableView:(ASTableView *)tableView constrainedSizeForRowAtIndexPath:(NSIndexPath *)indexPath; + /** * Informs the delegate that the table view did remove the node which was previously * at the given index path from the view hierarchy. diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index c978bb9e5e..f3f3177a9e 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -28,6 +28,7 @@ #import +static const ASSizeRange kInvalidSizeRange = {CGSizeZero, CGSizeZero}; static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; //#define LOG(...) NSLog(__VA_ARGS__) @@ -125,6 +126,7 @@ @interface ASTableView () )asyncDelegate _asyncDelegateFlags.asyncDelegateShouldBatchFetchForTableView = [_asyncDelegate respondsToSelector:@selector(shouldBatchFetchForTableView:)]; _asyncDelegateFlags.asyncDelegateScrollViewWillBeginDragging = [_asyncDelegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]; _asyncDelegateFlags.asyncDelegateScrollViewDidEndDragging = [_asyncDelegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]; + _asyncDelegateFlags.asyncDelegateTableViewConstrainedSizeForRowAtIndexPath = [_asyncDelegate respondsToSelector:@selector(tableView:constrainedSizeForRowAtIndexPath:)]; + } super.delegate = (id)_proxyDelegate; @@ -1069,8 +1073,17 @@ - (ASCellNodeBlock)dataController:(ASDataController *)dataController nodeBlockAt - (ASSizeRange)dataController:(ASDataController *)dataController constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath { - return ASSizeRangeMake(CGSizeMake(_nodesConstrainedWidth, 0), - CGSizeMake(_nodesConstrainedWidth, FLT_MAX)); + ASSizeRange constrainedSize = kInvalidSizeRange; + if (_asyncDelegateFlags.asyncDelegateTableViewConstrainedSizeForRowAtIndexPath) { + ASSizeRange delegateConstrainedSize = [_asyncDelegate tableView:self constrainedSizeForRowAtIndexPath:indexPath]; + // ignore widths in the returned size range (for TableView) + constrainedSize = ASSizeRangeMake(CGSizeMake(_nodesConstrainedWidth, delegateConstrainedSize.min.height), + CGSizeMake(_nodesConstrainedWidth, delegateConstrainedSize.max.height)); + } else { + constrainedSize = ASSizeRangeMake(CGSizeMake(_nodesConstrainedWidth, 0), + CGSizeMake(_nodesConstrainedWidth, FLT_MAX)); + } + return constrainedSize; } - (NSUInteger)dataController:(ASDataController *)dataController rowsInSection:(NSUInteger)section diff --git a/AsyncDisplayKitTests/ASTableViewTests.m b/AsyncDisplayKitTests/ASTableViewTests.m index 7cb13fb8ca..98914d1bd4 100644 --- a/AsyncDisplayKitTests/ASTableViewTests.m +++ b/AsyncDisplayKitTests/ASTableViewTests.m @@ -128,7 +128,6 @@ - (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSInde return textCellNode; } - - (ASCellNodeBlock)tableView:(ASTableView *)tableView nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath { return ^{ @@ -140,12 +139,52 @@ - (ASCellNodeBlock)tableView:(ASTableView *)tableView nodeBlockForRowAtIndexPath @end +@interface ASTableViewFilledDelegate : NSObject +@end + +@implementation ASTableViewFilledDelegate + +- (ASSizeRange)tableView:(ASTableView *)tableView constrainedSizeForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return ASSizeRangeMakeExactSize(CGSizeMake(10, 42)); +} + +@end + @interface ASTableViewTests : XCTestCase @property (atomic, retain) ASTableView *testTableView; @end @implementation ASTableViewTests +- (void)testConstrainedSizeForRowAtIndexPath +{ + // Initial width of the table view is non-zero and all nodes are measured with this size. + // Any subsequence size change must trigger a relayout. + // Width and height are swapped so that a later size change will simulate a rotation + ASTestTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectMake(0, 0, 100, 400) + style:UITableViewStylePlain]; + + ASTableViewFilledDelegate *delegate = [ASTableViewFilledDelegate new]; + ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new]; + + tableView.asyncDelegate = delegate; + tableView.asyncDataSource = dataSource; + + [tableView reloadDataImmediately]; + [tableView setNeedsLayout]; + [tableView layoutIfNeeded]; + + for (int section = 0; section < NumberOfSections; section++) { + for (int row = 0; row < NumberOfRowsPerSection; row++) { + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section]; + CGRect rect = [tableView rectForRowAtIndexPath:indexPath]; + XCTAssertEqual(rect.size.width, 100); // specified width should be ignored for table + XCTAssertEqual(rect.size.height, 42); + } + } +} + // TODO: Convert this to ARC. - (void)DISABLED_testTableViewDoesNotRetainItselfAndDelegate {