mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Introduce ASCollectionLayout and friends (#3130)
* Introduce ASCollectionViewLayout - `ASCollectionViewLayout` is an async `UICollectionViewLayout` that encapsulates its layout calculation logic into a separate thread-safe object which can be used ahead of time and/or on multiple threads. - `ASDataController` now can prepare for a new layout resulted from a change set before `ASCollectionView` even knows about it. By the time the change set it ready to be consumed by `ASCollectionView`, its new layout is also ready. - New `ASCollectionViewLayoutCalculating` protocol that is simple and generic enough that many types of calculators can be built on top. `ASCollectionViewLayoutSpecCalculator` conforms to `ASCollectionViewLayoutCalculating` protocol and can be backed by any layout spec (e.g `ASStackLayoutSpec`, `PIMasonryLayoutSpec`, etc). We can even build a `ASCollectionViewLayoutYogaCalculator` that uses Yoga internally. - A built-in `ASCollectionViewFlowLayoutCalculator` that is a subclass of `ASCollectionViewLayoutSpecCalculator` and uses a multi-threaded multi-line `ASStackLayoutSpec` internally. The result is a performant and thread-safe flow layout calculator. - Finally, `ASCollectionViewLayout` can be subclassed to handle a specific type of calculator with optimizations implemented based on the knowledge of such calculator. For example, `ASCollectionViewFlowLayout` can have a highly optimized implementation of `-layoutAttributesForElementsInRect:`. Protocolize layout calculator providing and consuming Add flex wrap documentation Add a `multithreaded` flag to ASStackLayoutSpec that forces it to dispatch even if it's off main - Update ASCollectionViewFlowLayoutSpecCalculator to use that flag. Minor change in ASCollectionViewLayout Implement Mosaic layout calculator Minor change Fix project file Rename and fix project file Skip fetching constrained size only if a layout calculator is available Update examples/ASCollectionView Remove unnecessary change in ASTableView Address comments Rename collection view calculator protocols Minor changes after rebasing with master Add ASLegacyCollectionLayoutCalculator for backward compatibility Remove ASCollectionLayoutSpecCalculator Remove ASLegacyCollectionLayoutCalculator Introduce ASCollectionLayout - A wrapper object that contains content size and an element to rect table. - Collection layout calculators to return this new object instead of an ASLayout. Before adding a content cache Finishing hooking up ASCollectionLayoutDataSource to ASCollectionNode Stash Finish ASCollectionLayout Rough impl of ASCollectionFlowLayout Revert changes in CustomCollectionView example Move ASRectTable back to Private * Rename ASCollectionContentAttributes to ASCollectionLayoutState * Address other comments * Introduce ASCollectionLayoutDelegate and make ASCollectionLayout private * Address comments * API tweaks: - Replace `-layoutContextWithElementMap:` in ASCollectionLayoutDelegate with `-additionalInfoForLayoutWithElements:`. The returned object is then stored in ASCollectionLayoutContext for later lookups. - ASCollectionLayoutContext has no public initializer. - ASDataControllerLayoutDelegate no longer requires a context of type ASCollectionLayoutContext but simply an `id`. This helps decouple ASDataController and ASCollectionLayout. - Rename `elementMap` to `elements`. - Rename `visibleMap` to `visibleElements`. - Other minor changes. * Rename ASCGSizeHash to ASHashFromCGSize * Make sure to call super in -[ASCollectionLayout prepareLayout] * Update example/ASCollectionView to use ASCollectionFlowLayoutDelegate * Remove unnecessary change
This commit is contained in:
@@ -14,7 +14,9 @@
|
||||
#import <AsyncDisplayKit/ASCellNode+Internal.h>
|
||||
#import <AsyncDisplayKit/ASCollectionElement.h>
|
||||
#import <AsyncDisplayKit/ASCollectionInternal.h>
|
||||
#import <AsyncDisplayKit/ASCollectionLayout.h>
|
||||
#import <AsyncDisplayKit/ASCollectionViewLayoutController.h>
|
||||
#import <AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h>
|
||||
#import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h>
|
||||
#import <AsyncDisplayKit/ASDataController.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||
@@ -23,16 +25,15 @@
|
||||
#import <AsyncDisplayKit/ASInternalHelpers.h>
|
||||
#import <AsyncDisplayKit/UICollectionViewLayout+ASConvenience.h>
|
||||
#import <AsyncDisplayKit/ASRangeController.h>
|
||||
#import <AsyncDisplayKit/ASCollectionNode.h>
|
||||
#import <AsyncDisplayKit/_ASCollectionViewCell.h>
|
||||
#import <AsyncDisplayKit/_ASDisplayLayer.h>
|
||||
#import <AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h>
|
||||
#import <AsyncDisplayKit/ASPagerNode.h>
|
||||
#import <AsyncDisplayKit/ASSectionContext.h>
|
||||
#import <AsyncDisplayKit/ASCollectionView+Undeprecated.h>
|
||||
#import <AsyncDisplayKit/_ASHierarchyChangeSet.h>
|
||||
#import <AsyncDisplayKit/CoreGraphics+ASConvenience.h>
|
||||
#import <AsyncDisplayKit/ASLayout.h>
|
||||
#import <AsyncDisplayKit/ASThread.h>
|
||||
|
||||
/**
|
||||
* A macro to get self.collectionNode and assign it to a local variable, or return
|
||||
@@ -213,6 +214,8 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
unsigned int didChangeCollectionViewDataSource:1;
|
||||
unsigned int didChangeCollectionViewDelegate:1;
|
||||
} _layoutInspectorFlags;
|
||||
|
||||
BOOL _hasDataControllerLayoutDelegate;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -292,6 +295,8 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
_retainedLayer = self.layer;
|
||||
}
|
||||
|
||||
[self _configureCollectionViewLayout:layout];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -533,10 +538,13 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCollectionViewLayout:(UICollectionViewLayout *)collectionViewLayout
|
||||
- (void)setCollectionViewLayout:(nonnull UICollectionViewLayout *)collectionViewLayout
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
[super setCollectionViewLayout:collectionViewLayout];
|
||||
|
||||
[self _configureCollectionViewLayout:collectionViewLayout];
|
||||
|
||||
// Trigger recreation of layout inspector with new collection view layout
|
||||
if (_layoutInspector != nil) {
|
||||
_layoutInspector = nil;
|
||||
@@ -747,6 +755,14 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
|
||||
#pragma mark Internal
|
||||
|
||||
- (void)_configureCollectionViewLayout:(nonnull UICollectionViewLayout *)layout
|
||||
{
|
||||
_hasDataControllerLayoutDelegate = [layout conformsToProtocol:@protocol(ASDataControllerLayoutDelegate)];
|
||||
if (_hasDataControllerLayoutDelegate) {
|
||||
_dataController.layoutDelegate = (id<ASDataControllerLayoutDelegate>)layout;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Performing nested batch updates with super (e.g. resizing a cell node & updating collection view during same frame)
|
||||
can cause super to throw data integrity exceptions because it checks the data source counts before
|
||||
@@ -1515,7 +1531,6 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASDataControllerSource
|
||||
|
||||
- (ASCellNodeBlock)dataController:(ASDataController *)dataController nodeBlockAtIndexPath:(NSIndexPath *)indexPath
|
||||
@@ -1578,11 +1593,6 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
return block;
|
||||
}
|
||||
|
||||
- (ASSizeRange)dataController:(ASDataController *)dataController constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return [self.layoutInspector collectionView:self constrainedSizeForNodeAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (NSUInteger)dataController:(ASDataController *)dataController rowsInSection:(NSUInteger)section
|
||||
{
|
||||
if (_asyncDataSourceFlags.collectionNodeNumberOfItemsInSection) {
|
||||
@@ -1677,6 +1687,11 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
}
|
||||
}
|
||||
|
||||
- (ASSizeRange)dataController:(ASDataController *)dataController constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return [self.layoutInspector collectionView:self constrainedSizeForNodeAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (ASSizeRange)dataController:(ASDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (_layoutInspectorFlags.constrainedSizeForSupplementaryNodeOfKindAtIndexPath) {
|
||||
@@ -1892,6 +1907,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
}
|
||||
|
||||
#pragma mark - ASCellNodeDelegate
|
||||
|
||||
- (void)nodeSelectedStateDidChange:(ASCellNode *)node
|
||||
{
|
||||
NSIndexPath *indexPath = [self indexPathForNode:node];
|
||||
@@ -2030,6 +2046,10 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
*/
|
||||
- (void)layer:(CALayer *)layer didChangeBoundsWithOldValue:(CGRect)oldBounds newValue:(CGRect)newBounds
|
||||
{
|
||||
if (_hasDataControllerLayoutDelegate) {
|
||||
// Let the layout delegate handle bounds changes if it's available.
|
||||
return;
|
||||
}
|
||||
if (self.collectionViewLayout == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user