mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Improve Table Performance, Especially When Using Section Index Bar (#2506)
* Only trigger table view height requery if row-node height changed * Make ASTableView handle the section index bar better * Remove outdated comment * Add a main thread assertion
This commit is contained in:
@@ -388,19 +388,24 @@ ASEnvironmentCollectionTableSetEnvironmentState(_environmentStateLock)
|
||||
|
||||
- (void)reloadDataInitiallyIfNeeded
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
if (!self.dataController.initialReloadDataHasBeenCalled) {
|
||||
[self reloadData];
|
||||
// Note: Just calling reloadData isn't enough here – we need to
|
||||
// ensure that _nodesConstrainedWidth is updated first.
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
[self reloadDataInitiallyIfNeeded];
|
||||
return [self.dataController numberOfRowsInSection:section];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSections
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
[self reloadDataInitiallyIfNeeded];
|
||||
return [self.dataController numberOfSections];
|
||||
}
|
||||
|
||||
@@ -129,6 +129,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
BOOL _isDeallocating;
|
||||
BOOL _performingBatchUpdates;
|
||||
NSMutableSet *_cellsForVisibilityUpdates;
|
||||
|
||||
// The section index overlay view, if there is one present.
|
||||
// This is useful because we need to measure our row nodes against (width - indexView.width).
|
||||
__weak UIView *_sectionIndexView;
|
||||
|
||||
struct {
|
||||
unsigned int scrollViewDidScroll:1;
|
||||
@@ -181,6 +185,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
unsigned int tableNodeCanMoveRow:1;
|
||||
unsigned int tableViewMoveRow:1;
|
||||
unsigned int tableNodeMoveRow:1;
|
||||
unsigned int sectionIndexMethods:1; // if both section index methods are implemented
|
||||
} _asyncDataSourceFlags;
|
||||
}
|
||||
|
||||
@@ -321,6 +326,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
_asyncDataSourceFlags.tableNodeNodeBlockForRow = [_asyncDataSource respondsToSelector:@selector(tableNode:nodeBlockForRowAtIndexPath:)];
|
||||
_asyncDataSourceFlags.tableViewCanMoveRow = [_asyncDataSource respondsToSelector:@selector(tableView:canMoveRowAtIndexPath:)];
|
||||
_asyncDataSourceFlags.tableViewMoveRow = [_asyncDataSource respondsToSelector:@selector(tableView:moveRowAtIndexPath:toIndexPath:)];
|
||||
_asyncDataSourceFlags.sectionIndexMethods = [_asyncDataSource respondsToSelector:@selector(sectionIndexTitlesForTableView:)] && [_asyncDataSource respondsToSelector:@selector(tableView:sectionForSectionIndexTitle:atIndex:)];
|
||||
|
||||
ASDisplayNodeAssert(_asyncDataSourceFlags.tableViewNodeBlockForRow
|
||||
|| _asyncDataSourceFlags.tableViewNodeForRow
|
||||
@@ -559,8 +565,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if (_nodesConstrainedWidth != self.bounds.size.width) {
|
||||
_nodesConstrainedWidth = self.bounds.size.width;
|
||||
CGFloat constrainedWidth = self.bounds.size.width - [self sectionIndexWidth];
|
||||
if (_nodesConstrainedWidth != constrainedWidth) {
|
||||
_nodesConstrainedWidth = constrainedWidth;
|
||||
|
||||
// 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.
|
||||
@@ -1512,10 +1519,15 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
// is the same for all cells (because there is no easy way to get that individual value before the node being assigned to a _ASTableViewCell).
|
||||
// Also, in many cases, some nodes may not need to be re-measured at all, such as when user enters and then immediately leaves editing mode.
|
||||
// To avoid premature optimization and making such assumption, as well as to keep ASTableView simple, re-measurement is strictly done on main.
|
||||
[self beginUpdates];
|
||||
CGSize oldSize = node.bounds.size;
|
||||
const CGSize calculatedSize = [node layoutThatFits:constrainedSize].size;
|
||||
node.frame = CGRectMake(0, 0, calculatedSize.width, calculatedSize.height);
|
||||
[self endUpdates];
|
||||
node.frame = { .size = calculatedSize };
|
||||
|
||||
// If the node height changed, trigger a height requery.
|
||||
if (oldSize.height != calculatedSize.height) {
|
||||
[self beginUpdates];
|
||||
[self endUpdates];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1579,6 +1591,31 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
// Note: This is called every layout, and so it is very performance sensitive.
|
||||
- (CGFloat)sectionIndexWidth
|
||||
{
|
||||
// If they don't implement the methods, then there's no section index.
|
||||
if (_asyncDataSourceFlags.sectionIndexMethods == NO) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
UIView *indexView = _sectionIndexView;
|
||||
if (indexView.superview == self) {
|
||||
return indexView.frame.size.width;
|
||||
}
|
||||
|
||||
CGRect bounds = self.bounds;
|
||||
for (UIView *view in self.subviews) {
|
||||
CGRect frame = view.frame;
|
||||
// Section index is right-aligned and less than half-width.
|
||||
if (CGRectGetMaxX(frame) == CGRectGetMaxX(bounds) && frame.size.width * 2 < bounds.size.width) {
|
||||
_sectionIndexView = view;
|
||||
return frame.size.width;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @note This should be a UIKit index path.
|
||||
- (BOOL)isIndexPath:(NSIndexPath *)indexPath immediateSuccessorOfIndexPath:(NSIndexPath *)anchor
|
||||
{
|
||||
|
||||
@@ -59,4 +59,7 @@
|
||||
*/
|
||||
- (NSArray<NSIndexPath *> *)convertIndexPathsToTableNode:(NSArray<NSIndexPath *> *)indexPaths;
|
||||
|
||||
/// Returns the width of the section index view on the right-hand side of the table, if one is present.
|
||||
- (CGFloat)sectionIndexWidth;
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user