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;
|
@class ASCellNode;
|
||||||
@protocol ASCollectionViewDataSource;
|
@protocol ASCollectionViewDataSource;
|
||||||
@protocol ASCollectionViewDelegate;
|
@protocol ASCollectionViewDelegate;
|
||||||
|
@protocol ASCollectionViewLayoutInspecting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node-based collection view.
|
* Node-based collection view.
|
||||||
@@ -80,6 +80,13 @@
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) CGFloat leadingScreensForBatching;
|
@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.
|
* 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.
|
* The asyncDataSource must be updated to reflect the changes before the update block completes.
|
||||||
@@ -119,7 +126,7 @@
|
|||||||
*/
|
*/
|
||||||
- (void)reloadData;
|
- (void)reloadData;
|
||||||
|
|
||||||
- (void)registerSupplementaryViewOfKind:(NSString *)elementKind;
|
- (void)registerSupplementaryNodeOfKind:(NSString *)elementKind;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts one or more sections.
|
* Inserts one or more sections.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#import "ASBatchFetching.h"
|
#import "ASBatchFetching.h"
|
||||||
#import "UICollectionViewLayout+ASConvenience.h"
|
#import "UICollectionViewLayout+ASConvenience.h"
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
|
#import "ASCollectionViewFlowLayoutInspector.h"
|
||||||
|
|
||||||
// FIXME: Temporary nonsense import until method names are finalized and exposed
|
// FIXME: Temporary nonsense import until method names are finalized and exposed
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
@@ -137,6 +138,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
ASCollectionDataController *_dataController;
|
ASCollectionDataController *_dataController;
|
||||||
ASRangeController *_rangeController;
|
ASRangeController *_rangeController;
|
||||||
ASCollectionViewLayoutController *_layoutController;
|
ASCollectionViewLayoutController *_layoutController;
|
||||||
|
ASCollectionViewFlowLayoutInspector *_flowLayoutInspector;
|
||||||
|
|
||||||
BOOL _performingBatchUpdates;
|
BOOL _performingBatchUpdates;
|
||||||
NSMutableArray *_batchUpdateBlocks;
|
NSMutableArray *_batchUpdateBlocks;
|
||||||
@@ -203,6 +205,10 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
_dataController.delegate = _rangeController;
|
_dataController.delegate = _rangeController;
|
||||||
_dataController.dataSource = self;
|
_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];
|
_batchContext = [[ASBatchContext alloc] init];
|
||||||
|
|
||||||
_leadingScreensForBatching = 1.0;
|
_leadingScreensForBatching = 1.0;
|
||||||
@@ -377,7 +383,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
[self performBatchAnimated:YES updates:updates completion:completion];
|
[self performBatchAnimated:YES updates:updates completion:completion];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)registerSupplementaryViewOfKind:(NSString *)elementKind
|
- (void)registerSupplementaryNodeOfKind:(NSString *)elementKind
|
||||||
{
|
{
|
||||||
[self registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:elementKind
|
[self registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:elementKind
|
||||||
withReuseIdentifier:[self __reuseIdentifierForKind:elementKind]];
|
withReuseIdentifier:[self __reuseIdentifierForKind:elementKind]];
|
||||||
@@ -677,6 +683,11 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
return constrainedSize;
|
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
|
- (NSUInteger)dataController:(ASDataController *)dataController rowsInSection:(NSUInteger)section
|
||||||
{
|
{
|
||||||
return [_asyncDataSource collectionView:self numberOfItemsInSection:section];
|
return [_asyncDataSource collectionView:self numberOfItemsInSection:section];
|
||||||
|
|||||||
@@ -17,9 +17,14 @@
|
|||||||
|
|
||||||
@protocol ASCollectionDataControllerSource <ASDataControllerSource>
|
@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;
|
- (NSUInteger)dataController:(ASCollectionDataController *)dataController numberOfSectionsForSupplementaryKind:(NSString *)kind;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,12 @@
|
|||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
#import "ASDataController+Subclasses.h"
|
#import "ASDataController+Subclasses.h"
|
||||||
|
|
||||||
|
@interface ASCollectionDataController ()
|
||||||
|
|
||||||
|
- (id<ASCollectionDataControllerSource>)collectionDataSource;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation ASCollectionDataController {
|
@implementation ASCollectionDataController {
|
||||||
NSMutableDictionary *_completedSupplementaryNodes;
|
NSMutableDictionary *_completedSupplementaryNodes;
|
||||||
NSMutableDictionary *_editingSupplementaryNodes;
|
NSMutableDictionary *_editingSupplementaryNodes;
|
||||||
@@ -24,21 +30,23 @@
|
|||||||
[self performEditCommandWithBlock:^{
|
[self performEditCommandWithBlock:^{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
[self accessDataSourceWithBlock:^{
|
[self accessDataSourceWithBlock:^{
|
||||||
NSArray *elementKinds = [self.collectionDataSource supplementaryKindsInDataController:self];
|
NSArray *elementKinds = [self.collectionDataSource supplementaryNodeKindsInDataController:self];
|
||||||
[elementKinds enumerateObjectsUsingBlock:^(NSString *kind, NSUInteger idx, BOOL * _Nonnull stop) {
|
[elementKinds enumerateObjectsUsingBlock:^(NSString *kind, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||||
_completedSupplementaryNodes[kind] = [NSMutableArray array];
|
_completedSupplementaryNodes[kind] = [NSMutableArray array];
|
||||||
_editingSupplementaryNodes[kind] = [NSMutableArray array];
|
_editingSupplementaryNodes[kind] = [NSMutableArray array];
|
||||||
|
|
||||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
NSMutableArray *indexPaths = [NSMutableArray array];
|
||||||
NSMutableArray *nodes = [NSMutableArray array];
|
NSMutableArray *nodes = [NSMutableArray array];
|
||||||
[self _populateAllNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths];
|
[self _populateSupplementaryNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths];
|
||||||
[self batchLayoutNodes:nodes atIndexPaths:indexPaths completion:nil];
|
[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];
|
NSUInteger sectionCount = [self.collectionDataSource dataController:self numberOfSectionsForSupplementaryKind:kind];
|
||||||
for (NSUInteger i = 0; i < sectionCount; i++) {
|
for (NSUInteger i = 0; i < sectionCount; i++) {
|
||||||
@@ -65,6 +73,7 @@
|
|||||||
|
|
||||||
#pragma mark - Internal Data Querying
|
#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
|
- (void)_insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths
|
||||||
{
|
{
|
||||||
if (indexPaths.count == 0)
|
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
|
- (void)_deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths
|
||||||
{
|
{
|
||||||
if (indexPaths.count == 0)
|
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)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
|
@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");
|
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++) {
|
for (NSUInteger k = j; k < j + batchCount; k++) {
|
||||||
ASCellNode *node = nodes[k];
|
ASCellNode *node = nodes[k];
|
||||||
if (!node.isNodeLoaded) {
|
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);
|
dispatch_group_wait(layoutGroup, DISPATCH_TIME_FOREVER);
|
||||||
free(nodeBoundSizes);
|
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;
|
NSUInteger blockSize = [[ASDataController class] parallelProcessorCount] * kASDataControllerSizingCountPerProcessor;
|
||||||
|
|
||||||
@@ -164,14 +164,15 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
NSArray *batchedIndexPaths = [indexPaths subarrayWithRange:batchedRange];
|
NSArray *batchedIndexPaths = [indexPaths subarrayWithRange:batchedRange];
|
||||||
NSArray *batchedNodes = [nodes 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
|
- (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
|
[self batchLayoutNodes:nodes atIndexPaths:indexPaths constrainedSize:^ASSizeRange(NSIndexPath *indexPath) {
|
||||||
[self batchLayoutNodes:nodes atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) {
|
return [_dataSource dataController:self constrainedSizeForNodeAtIndexPath:indexPath];
|
||||||
|
} completion:^(NSArray *nodes, NSArray *indexPaths) {
|
||||||
// Insert finished nodes into data storage
|
// Insert finished nodes into data storage
|
||||||
[self _insertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
[self _insertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -39,8 +39,8 @@
|
|||||||
_collectionView.asyncDelegate = self;
|
_collectionView.asyncDelegate = self;
|
||||||
_collectionView.backgroundColor = [UIColor whiteColor];
|
_collectionView.backgroundColor = [UIColor whiteColor];
|
||||||
|
|
||||||
[_collectionView registerSupplementaryViewOfKind:UICollectionElementKindSectionHeader];
|
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
||||||
[_collectionView registerSupplementaryViewOfKind:UICollectionElementKindSectionFooter];
|
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionFooter];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user