Skip to content

Commit da7a2a5

Browse files
leviLevi McCallum
authored andcommitted
Further implement data controller support and layout introspection
1 parent 658b78d commit da7a2a5

9 files changed

Lines changed: 121 additions & 20 deletions

AsyncDisplayKit/ASCollectionView.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
@class ASCellNode;
1818
@protocol ASCollectionViewDataSource;
1919
@protocol ASCollectionViewDelegate;
20-
20+
@protocol ASCollectionViewLayoutInspecting;
2121

2222
/**
2323
* Node-based collection view.
@@ -80,6 +80,13 @@
8080
*/
8181
@property (nonatomic, assign) CGFloat leadingScreensForBatching;
8282

83+
/**
84+
* Optional introspection object for the collection view's layout.
85+
*
86+
* TODO: Discuss more about this delegate
87+
*/
88+
@property (nonatomic, weak) id<ASCollectionViewLayoutInspecting> layoutDelegate;
89+
8390
/**
8491
* Perform a batch of updates asynchronously, optionally disabling all animations in the batch. This method must be called from the main thread.
8592
* The asyncDataSource must be updated to reflect the changes before the update block completes.
@@ -119,7 +126,7 @@
119126
*/
120127
- (void)reloadData;
121128

122-
- (void)registerSupplementaryViewOfKind:(NSString *)elementKind;
129+
- (void)registerSupplementaryNodeOfKind:(NSString *)elementKind;
123130

124131
/**
125132
* Inserts one or more sections.

AsyncDisplayKit/ASCollectionView.mm

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#import "ASBatchFetching.h"
1717
#import "UICollectionViewLayout+ASConvenience.h"
1818
#import "ASInternalHelpers.h"
19+
#import "ASCollectionViewFlowLayoutInspector.h"
1920

2021
// FIXME: Temporary nonsense import until method names are finalized and exposed
2122
#import "ASDisplayNode+Subclasses.h"
@@ -137,6 +138,7 @@ @interface ASCollectionView () <ASRangeControllerDelegate, ASDataControllerSourc
137138
ASCollectionDataController *_dataController;
138139
ASRangeController *_rangeController;
139140
ASCollectionViewLayoutController *_layoutController;
141+
ASCollectionViewFlowLayoutInspector *_flowLayoutInspector;
140142

141143
BOOL _performingBatchUpdates;
142144
NSMutableArray *_batchUpdateBlocks;
@@ -202,7 +204,11 @@ - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionVi
202204
_dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:asyncDataFetchingEnabled];
203205
_dataController.delegate = _rangeController;
204206
_dataController.dataSource = self;
205-
207+
208+
_flowLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] init];
209+
// TODO: Implement a better path of falling-back to a flow layout
210+
_flowLayoutInspector.layout = (UICollectionViewFlowLayout *)layout;
211+
206212
_batchContext = [[ASBatchContext alloc] init];
207213

208214
_leadingScreensForBatching = 1.0;
@@ -377,7 +383,7 @@ - (void)performBatchUpdates:(void (^)())updates completion:(void (^)(BOOL))compl
377383
[self performBatchAnimated:YES updates:updates completion:completion];
378384
}
379385

380-
- (void)registerSupplementaryViewOfKind:(NSString *)elementKind
386+
- (void)registerSupplementaryNodeOfKind:(NSString *)elementKind
381387
{
382388
[self registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:elementKind
383389
withReuseIdentifier:[self __reuseIdentifierForKind:elementKind]];
@@ -677,6 +683,11 @@ - (ASSizeRange)dataController:(ASDataController *)dataController constrainedSize
677683
return constrainedSize;
678684
}
679685

686+
- (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
687+
{
688+
return [self.layoutDelegate collectionView:self constrainedSizeForSupplementaryNodeOfKind:kind atIndexPath:indexPath];
689+
}
690+
680691
- (NSUInteger)dataController:(ASDataController *)dataController rowsInSection:(NSUInteger)section
681692
{
682693
return [_asyncDataSource collectionView:self numberOfItemsInSection:section];

AsyncDisplayKit/Details/ASCollectionDataController.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717

1818
@protocol ASCollectionDataControllerSource <ASDataControllerSource>
1919

20-
- (ASDisplayNode *)dataController:(ASDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
20+
- (ASDisplayNode *)dataController:(ASCollectionDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
2121

22-
- (NSArray *)supplementaryKindsInDataController:(ASCollectionDataController *)dataController;
22+
/**
23+
The constrained size range for layout.
24+
*/
25+
- (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
26+
27+
- (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController;
2328

2429
- (NSUInteger)dataController:(ASCollectionDataController *)dataController numberOfSectionsForSupplementaryKind:(NSString *)kind;
2530

AsyncDisplayKit/Details/ASCollectionDataController.mm

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
#import "ASDisplayNodeInternal.h"
1515
#import "ASDataController+Subclasses.h"
1616

17+
@interface ASCollectionDataController ()
18+
19+
- (id<ASCollectionDataControllerSource>)collectionDataSource;
20+
21+
@end
22+
1723
@implementation ASCollectionDataController {
1824
NSMutableDictionary *_completedSupplementaryNodes;
1925
NSMutableDictionary *_editingSupplementaryNodes;
@@ -24,21 +30,23 @@ - (void)initialSupplementaryLoading
2430
[self performEditCommandWithBlock:^{
2531
ASDisplayNodeAssertMainThread();
2632
[self accessDataSourceWithBlock:^{
27-
NSArray *elementKinds = [self.collectionDataSource supplementaryKindsInDataController:self];
33+
NSArray *elementKinds = [self.collectionDataSource supplementaryNodeKindsInDataController:self];
2834
[elementKinds enumerateObjectsUsingBlock:^(NSString *kind, NSUInteger idx, BOOL * _Nonnull stop) {
2935
_completedSupplementaryNodes[kind] = [NSMutableArray array];
3036
_editingSupplementaryNodes[kind] = [NSMutableArray array];
3137

3238
NSMutableArray *indexPaths = [NSMutableArray array];
3339
NSMutableArray *nodes = [NSMutableArray array];
34-
[self _populateAllNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths];
35-
[self batchLayoutNodes:nodes atIndexPaths:indexPaths completion:nil];
40+
[self _populateSupplementaryNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths];
41+
[self batchLayoutNodes:nodes atIndexPaths:indexPaths constrainedSize:^ASSizeRange(NSIndexPath *indexPath) {
42+
return [self.collectionDataSource dataController:self constrainedSizeForSupplementaryNodeOfKind:kind atIndexPath:indexPath];
43+
} completion:nil];
3644
}];
3745
}];
3846
}];
3947
}
4048

41-
- (void)_populateAllNodesOfKind:(NSString *)kind withMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
49+
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
4250
{
4351
NSUInteger sectionCount = [self.collectionDataSource dataController:self numberOfSectionsForSupplementaryKind:kind];
4452
for (NSUInteger i = 0; i < sectionCount; i++) {
@@ -65,6 +73,7 @@ - (ASDisplayNode *)supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndex
6573

6674
#pragma mark - Internal Data Querying
6775

76+
// TODO: Reduce code duplication by exposing generic insert/delete helpers from ASDataController
6877
- (void)_insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths
6978
{
7079
if (indexPaths.count == 0)
@@ -78,6 +87,7 @@ - (void)_insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSAr
7887
});
7988
}
8089

90+
// TODO: Reduce code duplication by exposing generic insert/delete helpers from ASDataController
8191
- (void)_deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths
8292
{
8393
if (indexPaths.count == 0)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// ASCollectionViewFlowLayoutInspector.h
3+
// Pods
4+
//
5+
// Created by Levi McCallum on 9/29/15.
6+
//
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
#import <AsyncDisplayKit/ASDimension.h>
12+
13+
@class ASCollectionView;
14+
15+
@protocol ASCollectionViewLayoutInspecting <NSObject>
16+
17+
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
18+
19+
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryViewsOfKind:(NSString *)kind inSection:(NSUInteger)section;
20+
21+
@end
22+
23+
@interface ASCollectionViewFlowLayoutInspector : NSObject <ASCollectionViewLayoutInspecting>
24+
25+
@property (nonatomic, weak) UICollectionViewFlowLayout *layout;
26+
27+
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
28+
29+
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryViewsOfKind:(NSString *)kind inSection:(NSUInteger)section;
30+
31+
@end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// ASCollectionViewFlowLayoutInspector.m
3+
// Pods
4+
//
5+
// Created by Levi McCallum on 9/29/15.
6+
//
7+
//
8+
9+
#import "ASCollectionViewFlowLayoutInspector.h"
10+
11+
#import "ASCollectionView.h"
12+
13+
@implementation ASCollectionViewFlowLayoutInspector
14+
15+
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
16+
{
17+
// TODO: Implement some heuristic that follows the width/height constraints of header and footer supplementary views
18+
return ASSizeRangeMake(CGSizeZero, CGSizeMake(FLT_MAX, FLT_MAX));
19+
}
20+
21+
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryViewsOfKind:(NSString *)kind inSection:(NSUInteger)section
22+
{
23+
NSUInteger count = 0;
24+
if (self.layout.headerReferenceSize.width > 0 || self.layout.headerReferenceSize.height > 0) {
25+
count++;
26+
}
27+
if (self.layout.footerReferenceSize.width > 0 || self.layout.footerReferenceSize.height > 0) {
28+
count++;
29+
}
30+
return count;
31+
}
32+
33+
@end

AsyncDisplayKit/Details/ASDataController+Subclasses.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
*/
2626
- (void)accessDataSourceWithBlock:(dispatch_block_t)block;
2727

28-
- (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))block;
28+
/**
29+
* Measure and layout the given nodes in optimized batches, constraining each to a given size.
30+
*/
31+
- (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths constrainedSize:(ASSizeRange (^)(NSIndexPath *indexPath))constraintedSizeBlock completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock;
2932

3033
@end

AsyncDisplayKit/Details/ASDataController.mm

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ - (void)_layoutNodesWithMainThreadAffinity:(NSArray *)nodes atIndexPaths:(NSArra
113113
}];
114114
}
115115

116-
- (void)_layoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *, NSArray *))block
116+
- (void)_layoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths constrainedSize:(ASSizeRange (^)(NSIndexPath *indexPath))constraintedSizeBlock completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock
117117
{
118118
ASDisplayNodeAssert([NSOperationQueue currentQueue] == _editingTransactionQueue, @"Cell node layout must be initiated from edit transaction queue");
119119

@@ -129,7 +129,7 @@ - (void)_layoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths complet
129129
for (NSUInteger k = j; k < j + batchCount; k++) {
130130
ASCellNode *node = nodes[k];
131131
if (!node.isNodeLoaded) {
132-
nodeBoundSizes[k] = [_dataSource dataController:self constrainedSizeForNodeAtIndexPath:indexPaths[k]];
132+
nodeBoundSizes[k] = constraintedSizeBlock(indexPaths[k]);
133133
}
134134
}
135135

@@ -151,10 +151,10 @@ - (void)_layoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths complet
151151
dispatch_group_wait(layoutGroup, DISPATCH_TIME_FOREVER);
152152
free(nodeBoundSizes);
153153

154-
block(nodes, indexPaths);
154+
completionBlock(nodes, indexPaths);
155155
}
156156

157-
- (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))block
157+
- (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths constrainedSize:(ASSizeRange (^)(NSIndexPath *indexPath))constraintedSizeBlock completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock
158158
{
159159
NSUInteger blockSize = [[ASDataController class] parallelProcessorCount] * kASDataControllerSizingCountPerProcessor;
160160

@@ -164,14 +164,15 @@ - (void)batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths com
164164
NSArray *batchedIndexPaths = [indexPaths subarrayWithRange:batchedRange];
165165
NSArray *batchedNodes = [nodes subarrayWithRange:batchedRange];
166166

167-
[self _layoutNodes:batchedNodes atIndexPaths:batchedIndexPaths completion:block];
167+
[self _layoutNodes:batchedNodes atIndexPaths:batchedIndexPaths constrainedSize:constraintedSizeBlock completion:completionBlock];
168168
}
169169
}
170170

171171
- (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
172172
{
173-
174-
[self batchLayoutNodes:nodes atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) {
173+
[self batchLayoutNodes:nodes atIndexPaths:indexPaths constrainedSize:^ASSizeRange(NSIndexPath *indexPath) {
174+
return [_dataSource dataController:self constrainedSizeForNodeAtIndexPath:indexPath];
175+
} completion:^(NSArray *nodes, NSArray *indexPaths) {
175176
// Insert finished nodes into data storage
176177
[self _insertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
177178
}];

examples/ASCollectionView/Sample/ViewController.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ - (instancetype)init
3939
_collectionView.asyncDelegate = self;
4040
_collectionView.backgroundColor = [UIColor whiteColor];
4141

42-
[_collectionView registerSupplementaryViewOfKind:UICollectionElementKindSectionHeader];
43-
[_collectionView registerSupplementaryViewOfKind:UICollectionElementKindSectionFooter];
42+
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
43+
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionFooter];
4444

4545
return self;
4646
}

0 commit comments

Comments
 (0)