Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions AsyncDisplayKit/ASTableView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ @interface ASTableView () <ASRangeControllerDelegate, ASDataControllerSource, _A
NSIndexPath *_contentOffsetAdjustmentTopVisibleRow;
CGFloat _contentOffsetAdjustment;

CGFloat _maxWidthForNodesConstrainedSize;
BOOL _ignoreMaxWidthChange;
CGFloat _nodesConstrainedWidth;
BOOL _ignoreNodesConstrainedWidthChange;
}

@property (atomic, assign) BOOL asyncDataSourceLocked;
Expand Down Expand Up @@ -224,10 +224,10 @@ - (void)configureWithAsyncDataFetching:(BOOL)asyncDataFetchingEnabled

_automaticallyAdjustsContentOffset = NO;

_maxWidthForNodesConstrainedSize = self.bounds.size.width;
_nodesConstrainedWidth = self.bounds.size.width;
// If the initial size is 0, expect a size change very soon which is part of the initial configuration
// and should not trigger a relayout.
_ignoreMaxWidthChange = (_maxWidthForNodesConstrainedSize == 0);
_ignoreNodesConstrainedWidthChange = (_nodesConstrainedWidth == 0);
}

- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
Expand Down Expand Up @@ -396,13 +396,13 @@ - (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL completed))c

- (void)layoutSubviews
{
if (_maxWidthForNodesConstrainedSize != self.bounds.size.width) {
_maxWidthForNodesConstrainedSize = self.bounds.size.width;
if (_nodesConstrainedWidth != self.bounds.size.width) {
_nodesConstrainedWidth = self.bounds.size.width;

// First width change occurs during initial configuration. An expensive relayout pass is unnecessary at that time
// and should be avoided, assuming that the initial data loading automatically runs shortly afterward.
if (_ignoreMaxWidthChange) {
_ignoreMaxWidthChange = NO;
if (_ignoreNodesConstrainedWidthChange) {
_ignoreNodesConstrainedWidthChange = NO;
} else {
[self beginUpdates];
[_dataController relayoutAllNodes];
Expand Down Expand Up @@ -828,8 +828,8 @@ - (ASCellNode *)dataController:(ASDataController *)dataController nodeAtIndexPat

- (ASSizeRange)dataController:(ASDataController *)dataController constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{
return ASSizeRangeMake(CGSizeMake(_maxWidthForNodesConstrainedSize, 0),
CGSizeMake(_maxWidthForNodesConstrainedSize, FLT_MAX));
return ASSizeRangeMake(CGSizeMake(_nodesConstrainedWidth, 0),
CGSizeMake(_nodesConstrainedWidth, FLT_MAX));
}

- (void)dataControllerLockDataSource
Expand Down Expand Up @@ -880,7 +880,7 @@ - (void)willLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell
// Normally the content view width equals to the constrained size width (which equals to the table view width).
// If there is a mismatch between these values, for example after the table view entered or left editing mode,
// content view width is preferred and used to re-measure the cell node.
if (contentViewWidth != constrainedSize.max.width) {
if (!_ignoreNodesConstrainedWidthChange && contentViewWidth != constrainedSize.max.width) {
constrainedSize.min.width = contentViewWidth;
constrainedSize.max.width = contentViewWidth;

Expand Down
121 changes: 53 additions & 68 deletions AsyncDisplayKitTests/ASTableViewTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,7 @@ - (void)testRelayoutAllRowsWithNonZeroSizeInitially
tableView.asyncDelegate = dataSource;
tableView.asyncDataSource = dataSource;

// Trigger layout measurement on all nodes
[tableView reloadData];

[self triggerFirstLayoutMeasurementForTableView:tableView];
[self triggerSizeChangeAndAssertRelayoutAllRowsForTableView:tableView newSize:tableViewFinalSize];
}

Expand Down Expand Up @@ -264,36 +262,6 @@ - (void)testRelayoutAllRowsWithZeroSizeInitially
[self triggerSizeChangeAndAssertRelayoutAllRowsForTableView:tableView newSize:tableViewFinalSize];
}

- (void)triggerSizeChangeAndAssertRelayoutAllRowsForTableView:(ASTableView *)tableView newSize:(CGSize)newSize
{
XCTestExpectation *nodesMeasuredUsingNewConstrainedSizeExpectation = [self expectationWithDescription:@"nodesMeasuredUsingNewConstrainedSize"];

[tableView beginUpdates];

CGRect frame = tableView.frame;
frame.size = newSize;
tableView.frame = frame;
[tableView layoutIfNeeded];

[tableView endUpdatesAnimated:NO completion:^(BOOL completed) {
for (int section = 0; section < NumberOfSections; section++) {
for (int row = 0; row < NumberOfRowsPerSection; row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
ASTestTextCellNode *node = (ASTestTextCellNode *)[tableView nodeForRowAtIndexPath:indexPath];
XCTAssertEqual(node.numberOfLayoutsOnMainThread, 1);
XCTAssertEqual(node.constrainedSizeForCalculatedLayout.max.width, newSize.width);
}
}
[nodesMeasuredUsingNewConstrainedSizeExpectation fulfill];
}];

[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(@"Expectation failed: %@", error);
}
}];
}

- (void)testRelayoutVisibleRowsWhenEditingModeIsChanged
{
CGSize tableViewSize = CGSizeMake(100, 500);
Expand All @@ -304,24 +272,8 @@ - (void)testRelayoutVisibleRowsWhenEditingModeIsChanged

tableView.asyncDelegate = dataSource;
tableView.asyncDataSource = dataSource;

XCTestExpectation *reloadDataExpectation = [self expectationWithDescription:@"reloadData"];
[tableView reloadDataWithCompletion:^{
for (int section = 0; section < NumberOfSections; section++) {
for (int row = 0; row < NumberOfRowsPerSection; row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
ASTestTextCellNode *node = (ASTestTextCellNode *)[tableView nodeForRowAtIndexPath:indexPath];
XCTAssertEqual(node.numberOfLayoutsOnMainThread, 0);
XCTAssertEqual(node.constrainedSizeForCalculatedLayout.max.width, tableViewSize.width);
}
}
[reloadDataExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(@"Expectation failed: %@", error);
}
}];

[self triggerFirstLayoutMeasurementForTableView:tableView];

NSArray *visibleNodes = [tableView visibleNodes];
XCTAssertGreaterThan(visibleNodes.count, 0);
Expand Down Expand Up @@ -390,23 +342,7 @@ - (void)DISABLED_testRelayoutRowsAfterEditingModeIsChangedAndTheyBecomeVisible
tableView.asyncDelegate = dataSource;
tableView.asyncDataSource = dataSource;

XCTestExpectation *reloadDataExpectation = [self expectationWithDescription:@"reloadData"];
[tableView reloadDataWithCompletion:^{
for (int section = 0; section < NumberOfSections; section++) {
for (int row = 0; row < NumberOfRowsPerSection; row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
ASTestTextCellNode *node = (ASTestTextCellNode *)[tableView nodeForRowAtIndexPath:indexPath];
XCTAssertEqual(node.numberOfLayoutsOnMainThread, 0);
XCTAssertEqual(node.constrainedSizeForCalculatedLayout.max.width, tableViewSize.width);
}
}
[reloadDataExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(@"Expectation failed: %@", error);
}
}];
[self triggerFirstLayoutMeasurementForTableView:tableView];

// Cause table view to enter editing mode and then scroll to the bottom.
// The last node should be re-measured on main thread with the new (smaller) content view width.
Expand Down Expand Up @@ -451,4 +387,53 @@ - (void)testIndexPathForNode
}];
}

- (void)triggerFirstLayoutMeasurementForTableView:(ASTableView *)tableView{
XCTestExpectation *reloadDataExpectation = [self expectationWithDescription:@"reloadData"];
[tableView reloadDataWithCompletion:^{
for (int section = 0; section < NumberOfSections; section++) {
for (int row = 0; row < NumberOfRowsPerSection; row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
ASTestTextCellNode *node = (ASTestTextCellNode *)[tableView nodeForRowAtIndexPath:indexPath];
XCTAssertEqual(node.numberOfLayoutsOnMainThread, 0);
XCTAssertEqual(node.constrainedSizeForCalculatedLayout.max.width, tableView.frame.size.width);
}
}
[reloadDataExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(@"Expectation failed: %@", error);
}
}];
}

- (void)triggerSizeChangeAndAssertRelayoutAllRowsForTableView:(ASTableView *)tableView newSize:(CGSize)newSize
{
XCTestExpectation *nodesMeasuredUsingNewConstrainedSizeExpectation = [self expectationWithDescription:@"nodesMeasuredUsingNewConstrainedSize"];

[tableView beginUpdates];

CGRect frame = tableView.frame;
frame.size = newSize;
tableView.frame = frame;
[tableView layoutIfNeeded];

[tableView endUpdatesAnimated:NO completion:^(BOOL completed) {
for (int section = 0; section < NumberOfSections; section++) {
for (int row = 0; row < NumberOfRowsPerSection; row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
ASTestTextCellNode *node = (ASTestTextCellNode *)[tableView nodeForRowAtIndexPath:indexPath];
XCTAssertEqual(node.numberOfLayoutsOnMainThread, 1);
XCTAssertEqual(node.constrainedSizeForCalculatedLayout.max.width, newSize.width);
}
}
[nodesMeasuredUsingNewConstrainedSizeExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(@"Expectation failed: %@", error);
}
}];
}

@end