Avoid doing relayout during initial configuration of table and collection views.

This commit is contained in:
Huy Nguyen
2015-09-08 22:31:09 +03:00
parent 6383b69029
commit a8cecbd0ad
2 changed files with 34 additions and 10 deletions

View File

@@ -126,6 +126,7 @@ static BOOL _isInterceptedSelector(SEL sel)
ASBatchContext *_batchContext;
CGSize _maxSizeForNodesConstrainedSize;
BOOL _ignoreMaxSizeChange;
}
@property (atomic, assign) BOOL asyncDataSourceLocked;
@@ -179,6 +180,9 @@ static BOOL _isInterceptedSelector(SEL sel)
_collectionViewLayoutImplementsInsetSection = [layout respondsToSelector:@selector(sectionInset)];
_maxSizeForNodesConstrainedSize = self.bounds.size;
// 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.
_ignoreMaxSizeChange = CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, CGSizeZero);
self.backgroundColor = [UIColor whiteColor];
@@ -481,14 +485,22 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)layoutSubviews
{
[super layoutSubviews];
if (! CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, self.bounds.size)) {
_maxSizeForNodesConstrainedSize = self.bounds.size;
[self performBatchAnimated:NO updates:^{
[_dataController relayoutAllRows];
} completion:nil];
// First size 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 (_ignoreMaxSizeChange) {
_ignoreMaxSizeChange = NO;
} else {
[self performBatchAnimated:NO updates:^{
[_dataController relayoutAllRows];
} completion:nil];
}
}
// To ensure _maxSizeForNodesConstrainedSize is up-to-date for every usage, this call to super must be done last
[super layoutSubviews];
}

View File

@@ -149,6 +149,7 @@ static BOOL _isInterceptedSelector(SEL sel)
BOOL _asyncDataSourceImplementsConstrainedSizeForNode;
CGFloat _maxWidthForNodesConstrainedSize;
BOOL _ignoreMaxWidthChange;
}
@property (atomic, assign) BOOL asyncDataSourceLocked;
@@ -203,6 +204,9 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
_automaticallyAdjustsContentOffset = NO;
_maxWidthForNodesConstrainedSize = 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);
}
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
@@ -367,14 +371,22 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
- (void)layoutSubviews
{
[super layoutSubviews];
if (_maxWidthForNodesConstrainedSize != self.bounds.size.width) {
_maxWidthForNodesConstrainedSize = self.bounds.size.width;
[self beginUpdates];
[_dataController relayoutAllRows];
[self endUpdates];
// 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;
} else {
[self beginUpdates];
[_dataController relayoutAllRows];
[self endUpdates];
}
}
// To ensure _maxWidthForNodesConstrainedSize is up-to-date for every usage, this call to super must be done last
[super layoutSubviews];
}
#pragma mark -