mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Further implement data controller support and layout introspection
This commit is contained in:
committed by
Levi McCallum
parent
658b78d552
commit
da7a2a5d48
@@ -17,7 +17,7 @@
|
||||
@class ASCellNode;
|
||||
@protocol ASCollectionViewDataSource;
|
||||
@protocol ASCollectionViewDelegate;
|
||||
|
||||
@protocol ASCollectionViewLayoutInspecting;
|
||||
|
||||
/**
|
||||
* Node-based collection view.
|
||||
@@ -80,6 +80,13 @@
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat leadingScreensForBatching;
|
||||
|
||||
/**
|
||||
* Optional introspection object for the collection view's layout.
|
||||
*
|
||||
* TODO: Discuss more about this delegate
|
||||
*/
|
||||
@property (nonatomic, weak) id<ASCollectionViewLayoutInspecting> layoutDelegate;
|
||||
|
||||
/**
|
||||
* Perform a batch of updates asynchronously, optionally disabling all animations in the batch. This method must be called from the main thread.
|
||||
* The asyncDataSource must be updated to reflect the changes before the update block completes.
|
||||
@@ -119,7 +126,7 @@
|
||||
*/
|
||||
- (void)reloadData;
|
||||
|
||||
- (void)registerSupplementaryViewOfKind:(NSString *)elementKind;
|
||||
- (void)registerSupplementaryNodeOfKind:(NSString *)elementKind;
|
||||
|
||||
/**
|
||||
* Inserts one or more sections.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#import "ASBatchFetching.h"
|
||||
#import "UICollectionViewLayout+ASConvenience.h"
|
||||
#import "ASInternalHelpers.h"
|
||||
#import "ASCollectionViewFlowLayoutInspector.h"
|
||||
|
||||
// FIXME: Temporary nonsense import until method names are finalized and exposed
|
||||
#import "ASDisplayNode+Subclasses.h"
|
||||
@@ -137,6 +138,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
||||
ASCollectionDataController *_dataController;
|
||||
ASRangeController *_rangeController;
|
||||
ASCollectionViewLayoutController *_layoutController;
|
||||
ASCollectionViewFlowLayoutInspector *_flowLayoutInspector;
|
||||
|
||||
BOOL _performingBatchUpdates;
|
||||
NSMutableArray *_batchUpdateBlocks;
|
||||
@@ -203,6 +205,10 @@ static BOOL _isInterceptedSelector(SEL sel)
|
||||
_dataController.delegate = _rangeController;
|
||||
_dataController.dataSource = self;
|
||||
|
||||
_flowLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] init];
|
||||
// TODO: Implement a better path of falling-back to a flow layout
|
||||
_flowLayoutInspector.layout = (UICollectionViewFlowLayout *)layout;
|
||||
|
||||
_batchContext = [[ASBatchContext alloc] init];
|
||||
|
||||
_leadingScreensForBatching = 1.0;
|
||||
@@ -377,7 +383,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
||||
[self performBatchAnimated:YES updates:updates completion:completion];
|
||||
}
|
||||
|
||||
- (void)registerSupplementaryViewOfKind:(NSString *)elementKind
|
||||
- (void)registerSupplementaryNodeOfKind:(NSString *)elementKind
|
||||
{
|
||||
[self registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:elementKind
|
||||
withReuseIdentifier:[self __reuseIdentifierForKind:elementKind]];
|
||||
@@ -677,6 +683,11 @@ static BOOL _isInterceptedSelector(SEL sel)
|
||||
return constrainedSize;
|
||||
}
|
||||
|
||||
- (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return [self.layoutDelegate collectionView:self constrainedSizeForSupplementaryNodeOfKind:kind atIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (NSUInteger)dataController:(ASDataController *)dataController rowsInSection:(NSUInteger)section
|
||||
{
|
||||
return [_asyncDataSource collectionView:self numberOfItemsInSection:section];
|
||||
|
||||
@@ -17,9 +17,14 @@
|
||||
|
||||
@protocol ASCollectionDataControllerSource <ASDataControllerSource>
|
||||
|
||||
- (ASDisplayNode *)dataController:(ASDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
||||
- (ASDisplayNode *)dataController:(ASCollectionDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (NSArray *)supplementaryKindsInDataController:(ASCollectionDataController *)dataController;
|
||||
/**
|
||||
The constrained size range for layout.
|
||||
*/
|
||||
- (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController;
|
||||
|
||||
- (NSUInteger)dataController:(ASCollectionDataController *)dataController numberOfSectionsForSupplementaryKind:(NSString *)kind;
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
#import "ASDisplayNodeInternal.h"
|
||||
#import "ASDataController+Subclasses.h"
|
||||
|
||||
@interface ASCollectionDataController ()
|
||||
|
||||
- (id<ASCollectionDataControllerSource>)collectionDataSource;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASCollectionDataController {
|
||||
NSMutableDictionary *_completedSupplementaryNodes;
|
||||
NSMutableDictionary *_editingSupplementaryNodes;
|
||||
@@ -24,21 +30,23 @@
|
||||
[self performEditCommandWithBlock:^{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
[self accessDataSourceWithBlock:^{
|
||||
NSArray *elementKinds = [self.collectionDataSource supplementaryKindsInDataController:self];
|
||||
NSArray *elementKinds = [self.collectionDataSource supplementaryNodeKindsInDataController:self];
|
||||
[elementKinds enumerateObjectsUsingBlock:^(NSString *kind, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
_completedSupplementaryNodes[kind] = [NSMutableArray array];
|
||||
_editingSupplementaryNodes[kind] = [NSMutableArray array];
|
||||
|
||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
||||
NSMutableArray *nodes = [NSMutableArray array];
|
||||
[self _populateAllNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths];
|
||||
[self batchLayoutNodes:nodes atIndexPaths:indexPaths completion:nil];
|
||||
[self _populateSupplementaryNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths];
|
||||
[self batchLayoutNodes:nodes atIndexPaths:indexPaths constrainedSize:^ASSizeRange(NSIndexPath *indexPath) {
|
||||
return [self.collectionDataSource dataController:self constrainedSizeForSupplementaryNodeOfKind:kind atIndexPath:indexPath];
|
||||
} completion:nil];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)_populateAllNodesOfKind:(NSString *)kind withMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
|
||||
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
|
||||
{
|
||||
NSUInteger sectionCount = [self.collectionDataSource dataController:self numberOfSectionsForSupplementaryKind:kind];
|
||||
for (NSUInteger i = 0; i < sectionCount; i++) {
|
||||
@@ -65,6 +73,7 @@
|
||||
|
||||
#pragma mark - Internal Data Querying
|
||||
|
||||
// TODO: Reduce code duplication by exposing generic insert/delete helpers from ASDataController
|
||||
- (void)_insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths
|
||||
{
|
||||
if (indexPaths.count == 0)
|
||||
@@ -78,6 +87,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Reduce code duplication by exposing generic insert/delete helpers from ASDataController
|
||||
- (void)_deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths
|
||||
{
|
||||
if (indexPaths.count == 0)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// ASCollectionViewFlowLayoutInspector.h
|
||||
// Pods
|
||||
//
|
||||
// Created by Levi McCallum on 9/29/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <AsyncDisplayKit/ASDimension.h>
|
||||
|
||||
@class ASCollectionView;
|
||||
|
||||
@protocol ASCollectionViewLayoutInspecting <NSObject>
|
||||
|
||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryViewsOfKind:(NSString *)kind inSection:(NSUInteger)section;
|
||||
|
||||
@end
|
||||
|
||||
@interface ASCollectionViewFlowLayoutInspector : NSObject <ASCollectionViewLayoutInspecting>
|
||||
|
||||
@property (nonatomic, weak) UICollectionViewFlowLayout *layout;
|
||||
|
||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryViewsOfKind:(NSString *)kind inSection:(NSUInteger)section;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// ASCollectionViewFlowLayoutInspector.m
|
||||
// Pods
|
||||
//
|
||||
// Created by Levi McCallum on 9/29/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import "ASCollectionViewFlowLayoutInspector.h"
|
||||
|
||||
#import "ASCollectionView.h"
|
||||
|
||||
@implementation ASCollectionViewFlowLayoutInspector
|
||||
|
||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// TODO: Implement some heuristic that follows the width/height constraints of header and footer supplementary views
|
||||
return ASSizeRangeMake(CGSizeZero, CGSizeMake(FLT_MAX, FLT_MAX));
|
||||
}
|
||||
|
||||
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryViewsOfKind:(NSString *)kind inSection:(NSUInteger)section
|
||||
{
|
||||
NSUInteger count = 0;
|
||||
if (self.layout.headerReferenceSize.width > 0 || self.layout.headerReferenceSize.height > 0) {
|
||||
count++;
|
||||
}
|
||||
if (self.layout.footerReferenceSize.width > 0 || self.layout.footerReferenceSize.height > 0) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -25,6 +25,9 @@
|
||||
*/
|
||||
- (void)accessDataSourceWithBlock:(dispatch_block_t)block;
|
||||
|
||||
- (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))block;
|
||||
/**
|
||||
* Measure and layout the given nodes in optimized batches, constraining each to a given size.
|
||||
*/
|
||||
- (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths constrainedSize:(ASSizeRange (^)(NSIndexPath *indexPath))constraintedSizeBlock completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock;
|
||||
|
||||
@end
|
||||
|
||||
@@ -113,7 +113,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)_layoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *, NSArray *))block
|
||||
- (void)_layoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths constrainedSize:(ASSizeRange (^)(NSIndexPath *indexPath))constraintedSizeBlock completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock
|
||||
{
|
||||
ASDisplayNodeAssert([NSOperationQueue currentQueue] == _editingTransactionQueue, @"Cell node layout must be initiated from edit transaction queue");
|
||||
|
||||
@@ -129,7 +129,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
for (NSUInteger k = j; k < j + batchCount; k++) {
|
||||
ASCellNode *node = nodes[k];
|
||||
if (!node.isNodeLoaded) {
|
||||
nodeBoundSizes[k] = [_dataSource dataController:self constrainedSizeForNodeAtIndexPath:indexPaths[k]];
|
||||
nodeBoundSizes[k] = constraintedSizeBlock(indexPaths[k]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,10 +151,10 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
dispatch_group_wait(layoutGroup, DISPATCH_TIME_FOREVER);
|
||||
free(nodeBoundSizes);
|
||||
|
||||
block(nodes, indexPaths);
|
||||
completionBlock(nodes, indexPaths);
|
||||
}
|
||||
|
||||
- (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))block
|
||||
- (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths constrainedSize:(ASSizeRange (^)(NSIndexPath *indexPath))constraintedSizeBlock completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock
|
||||
{
|
||||
NSUInteger blockSize = [[ASDataController class] parallelProcessorCount] * kASDataControllerSizingCountPerProcessor;
|
||||
|
||||
@@ -164,14 +164,15 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
NSArray *batchedIndexPaths = [indexPaths subarrayWithRange:batchedRange];
|
||||
NSArray *batchedNodes = [nodes subarrayWithRange:batchedRange];
|
||||
|
||||
[self _layoutNodes:batchedNodes atIndexPaths:batchedIndexPaths completion:block];
|
||||
[self _layoutNodes:batchedNodes atIndexPaths:batchedIndexPaths constrainedSize:constraintedSizeBlock completion:completionBlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||
{
|
||||
|
||||
[self batchLayoutNodes:nodes atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) {
|
||||
[self batchLayoutNodes:nodes atIndexPaths:indexPaths constrainedSize:^ASSizeRange(NSIndexPath *indexPath) {
|
||||
return [_dataSource dataController:self constrainedSizeForNodeAtIndexPath:indexPath];
|
||||
} completion:^(NSArray *nodes, NSArray *indexPaths) {
|
||||
// Insert finished nodes into data storage
|
||||
[self _insertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||
}];
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
_collectionView.asyncDelegate = self;
|
||||
_collectionView.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
[_collectionView registerSupplementaryViewOfKind:UICollectionElementKindSectionHeader];
|
||||
[_collectionView registerSupplementaryViewOfKind:UICollectionElementKindSectionFooter];
|
||||
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
||||
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionFooter];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user