Skip to content

Commit e657bed

Browse files
committed
Automatically relayout cells after orientation changed.
1 parent 8da9ddd commit e657bed

6 files changed

Lines changed: 122 additions & 0 deletions

File tree

AsyncDisplayKit/ASCollectionView.mm

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#import "ASDisplayNodeInternal.h"
1616
#import "ASBatchFetching.h"
1717
#import "UICollectionViewLayout+ASConvenience.h"
18+
#import "ASInternalHelpers.h"
1819

1920
const static NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimationNone;
2021

@@ -121,6 +122,8 @@ @interface ASCollectionView () <ASRangeControllerDelegate, ASDataControllerSourc
121122
BOOL _implementsInsetSection;
122123

123124
ASBatchContext *_batchContext;
125+
126+
BOOL _pendingRelayoutForAllRows;
124127
}
125128

126129
@property (atomic, assign) BOOL asyncDataSourceLocked;
@@ -168,6 +171,11 @@ - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionVi
168171

169172
[self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"_ASCollectionViewCell"];
170173

174+
if (ASSystemVersionLessThan8()) {
175+
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
176+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];
177+
}
178+
171179
return self;
172180
}
173181

@@ -177,6 +185,11 @@ - (void)dealloc
177185
// This bug might be iOS 7-specific.
178186
super.delegate = nil;
179187
super.dataSource = nil;
188+
189+
if (ASSystemVersionLessThan8()) {
190+
[[NSNotificationCenter defaultCenter] removeObserver:self];
191+
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
192+
}
180193
}
181194

182195
#pragma mark -
@@ -462,6 +475,32 @@ - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(
462475
}
463476

464477

478+
#pragma mark -
479+
#pragma mark Orientation Change Handling
480+
481+
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
482+
{
483+
_pendingRelayoutForAllRows = YES;
484+
}
485+
486+
- (void)deviceOrientationDidChange
487+
{
488+
_pendingRelayoutForAllRows = YES;
489+
}
490+
491+
- (void)layoutSubviews
492+
{
493+
[super layoutSubviews];
494+
495+
if (_pendingRelayoutForAllRows) {
496+
_pendingRelayoutForAllRows = NO;
497+
[self performBatchAnimated:NO updates:^{
498+
[_dataController relayoutAllRows];
499+
} completion:nil];
500+
}
501+
}
502+
503+
465504
#pragma mark -
466505
#pragma mark Batch Fetching
467506

AsyncDisplayKit/ASTableView.mm

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#import "ASRangeController.h"
1616
#import "ASDisplayNodeInternal.h"
1717
#import "ASBatchFetching.h"
18+
#import "ASInternalHelpers.h"
1819

1920
//#define LOG(...) NSLog(__VA_ARGS__)
2021
#define LOG(...)
@@ -131,6 +132,8 @@ @interface ASTableView () <ASRangeControllerDelegate, ASDataControllerSource> {
131132

132133
NSIndexPath *_contentOffsetAdjustmentTopVisibleRow;
133134
CGFloat _contentOffsetAdjustment;
135+
136+
BOOL _pendingRelayoutForAllRows;
134137
}
135138

136139
@property (atomic, assign) BOOL asyncDataSourceLocked;
@@ -183,6 +186,11 @@ - (void)configureWithAsyncDataFetching:(BOOL)asyncDataFetchingEnabled
183186
_batchContext = [[ASBatchContext alloc] init];
184187

185188
_automaticallyAdjustsContentOffset = NO;
189+
190+
if (ASSystemVersionLessThan8()) {
191+
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
192+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];
193+
}
186194
}
187195

188196
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
@@ -220,6 +228,11 @@ - (void)dealloc
220228
// This bug might be iOS 7-specific.
221229
super.delegate = nil;
222230
super.dataSource = nil;
231+
232+
if (ASSystemVersionLessThan8()) {
233+
[[NSNotificationCenter defaultCenter] removeObserver:self];
234+
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
235+
}
223236
}
224237

225238
#pragma mark -
@@ -343,6 +356,31 @@ - (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL completed))c
343356
[_dataController endUpdatesAnimated:animated completion:completion];
344357
}
345358

359+
#pragma mark -
360+
#pragma mark Orientation Change Handling
361+
362+
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
363+
{
364+
_pendingRelayoutForAllRows = YES;
365+
}
366+
367+
- (void)deviceOrientationDidChange
368+
{
369+
_pendingRelayoutForAllRows = YES;
370+
}
371+
372+
- (void)layoutSubviews
373+
{
374+
[super layoutSubviews];
375+
376+
if (_pendingRelayoutForAllRows) {
377+
_pendingRelayoutForAllRows = NO;
378+
[self beginUpdates];
379+
[_dataController relayoutAllRows];
380+
[self endUpdates];
381+
}
382+
}
383+
346384
#pragma mark -
347385
#pragma mark Editing
348386

AsyncDisplayKit/Details/ASDataController.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ typedef NSUInteger ASDataControllerAnimationOptions;
154154

155155
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions;
156156

157+
/**
158+
* Re-measures all loaded nodes. Used for external relayout (relayout that is caused by a change in constrained size of each and every cell node,
159+
* for example, after an orientation change).
160+
*/
161+
- (void)relayoutAllRows;
162+
157163
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions;
158164

159165
- (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^)())completion;

AsyncDisplayKit/Details/ASDataController.mm

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,26 @@ - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDat
555555
}];
556556
}
557557

558+
- (void)relayoutAllRows
559+
{
560+
[self performEditCommandWithBlock:^{
561+
ASDisplayNodeAssertMainThread();
562+
LOG(@"Edit Command - relayoutRows");
563+
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
564+
565+
NSArray *indexPaths = ASIndexPathsForMultidimensionalArray(_completedNodes);
566+
NSArray *loadedNodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(_completedNodes, indexPaths);
567+
568+
for (NSUInteger i = 0; i < loadedNodes.count && i < indexPaths.count; i++) {
569+
// TODO: The current implementation does not make use of different constrained sizes per node.
570+
CGSize constrainedSize = [_dataSource dataController:self constrainedSizeForNodeAtIndexPath:indexPaths[i]];
571+
ASCellNode *node = loadedNodes[i];
572+
[node measure:constrainedSize];
573+
node.frame = CGRectMake(0.0f, 0.0f, node.calculatedSize.width, node.calculatedSize.height);
574+
}
575+
}];
576+
}
577+
558578
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
559579
{
560580
[self performEditCommandWithBlock:^{

AsyncDisplayKit/Private/ASInternalHelpers.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@ CGFloat ASCeilPixelValue(CGFloat f);
2424

2525
CGFloat ASRoundPixelValue(CGFloat f);
2626

27+
BOOL ASSystemVersionLessThan8();
28+
29+
BOOL ASSystemVersionLessThanVersion(NSString *version);
30+
2731
ASDISPLAYNODE_EXTERN_C_END

AsyncDisplayKit/Private/ASInternalHelpers.mm

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,18 @@ CGFloat ASRoundPixelValue(CGFloat f)
6161
{
6262
return roundf(f * ASScreenScale()) / ASScreenScale();
6363
}
64+
65+
BOOL ASSystemVersionLessThan8()
66+
{
67+
static BOOL lessThan8;
68+
static dispatch_once_t onceToken;
69+
dispatch_once(&onceToken, ^{
70+
lessThan8 = ASSystemVersionLessThanVersion(@"8");
71+
});
72+
return lessThan8;
73+
}
74+
75+
BOOL ASSystemVersionLessThanVersion(NSString *version)
76+
{
77+
return [[[UIDevice currentDevice] systemVersion] compare:version options:NSNumericSearch] == NSOrderedAscending;
78+
}

0 commit comments

Comments
 (0)