Automatically relayout cells after orientation changed.

This commit is contained in:
Huy Nguyen 2015-08-02 18:01:28 +03:00
parent 8da9ddd884
commit e657bedd40
6 changed files with 122 additions and 0 deletions

View File

@ -15,6 +15,7 @@
#import "ASDisplayNodeInternal.h" #import "ASDisplayNodeInternal.h"
#import "ASBatchFetching.h" #import "ASBatchFetching.h"
#import "UICollectionViewLayout+ASConvenience.h" #import "UICollectionViewLayout+ASConvenience.h"
#import "ASInternalHelpers.h"
const static NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimationNone; const static NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimationNone;
@ -121,6 +122,8 @@ static BOOL _isInterceptedSelector(SEL sel)
BOOL _implementsInsetSection; BOOL _implementsInsetSection;
ASBatchContext *_batchContext; ASBatchContext *_batchContext;
BOOL _pendingRelayoutForAllRows;
} }
@property (atomic, assign) BOOL asyncDataSourceLocked; @property (atomic, assign) BOOL asyncDataSourceLocked;
@ -168,6 +171,11 @@ static BOOL _isInterceptedSelector(SEL sel)
[self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"_ASCollectionViewCell"]; [self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"_ASCollectionViewCell"];
if (ASSystemVersionLessThan8()) {
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];
}
return self; return self;
} }
@ -177,6 +185,11 @@ static BOOL _isInterceptedSelector(SEL sel)
// This bug might be iOS 7-specific. // This bug might be iOS 7-specific.
super.delegate = nil; super.delegate = nil;
super.dataSource = nil; super.dataSource = nil;
if (ASSystemVersionLessThan8()) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
} }
#pragma mark - #pragma mark -
@ -462,6 +475,32 @@ static BOOL _isInterceptedSelector(SEL sel)
} }
#pragma mark -
#pragma mark Orientation Change Handling
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
_pendingRelayoutForAllRows = YES;
}
- (void)deviceOrientationDidChange
{
_pendingRelayoutForAllRows = YES;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (_pendingRelayoutForAllRows) {
_pendingRelayoutForAllRows = NO;
[self performBatchAnimated:NO updates:^{
[_dataController relayoutAllRows];
} completion:nil];
}
}
#pragma mark - #pragma mark -
#pragma mark Batch Fetching #pragma mark Batch Fetching

View File

@ -15,6 +15,7 @@
#import "ASRangeController.h" #import "ASRangeController.h"
#import "ASDisplayNodeInternal.h" #import "ASDisplayNodeInternal.h"
#import "ASBatchFetching.h" #import "ASBatchFetching.h"
#import "ASInternalHelpers.h"
//#define LOG(...) NSLog(__VA_ARGS__) //#define LOG(...) NSLog(__VA_ARGS__)
#define LOG(...) #define LOG(...)
@ -131,6 +132,8 @@ static BOOL _isInterceptedSelector(SEL sel)
NSIndexPath *_contentOffsetAdjustmentTopVisibleRow; NSIndexPath *_contentOffsetAdjustmentTopVisibleRow;
CGFloat _contentOffsetAdjustment; CGFloat _contentOffsetAdjustment;
BOOL _pendingRelayoutForAllRows;
} }
@property (atomic, assign) BOOL asyncDataSourceLocked; @property (atomic, assign) BOOL asyncDataSourceLocked;
@ -183,6 +186,11 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
_batchContext = [[ASBatchContext alloc] init]; _batchContext = [[ASBatchContext alloc] init];
_automaticallyAdjustsContentOffset = NO; _automaticallyAdjustsContentOffset = NO;
if (ASSystemVersionLessThan8()) {
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];
}
} }
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
@ -220,6 +228,11 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
// This bug might be iOS 7-specific. // This bug might be iOS 7-specific.
super.delegate = nil; super.delegate = nil;
super.dataSource = nil; super.dataSource = nil;
if (ASSystemVersionLessThan8()) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
} }
#pragma mark - #pragma mark -
@ -343,6 +356,31 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
[_dataController endUpdatesAnimated:animated completion:completion]; [_dataController endUpdatesAnimated:animated completion:completion];
} }
#pragma mark -
#pragma mark Orientation Change Handling
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
_pendingRelayoutForAllRows = YES;
}
- (void)deviceOrientationDidChange
{
_pendingRelayoutForAllRows = YES;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (_pendingRelayoutForAllRows) {
_pendingRelayoutForAllRows = NO;
[self beginUpdates];
[_dataController relayoutAllRows];
[self endUpdates];
}
}
#pragma mark - #pragma mark -
#pragma mark Editing #pragma mark Editing

View File

@ -154,6 +154,12 @@ typedef NSUInteger ASDataControllerAnimationOptions;
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions;
/**
* 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,
* for example, after an orientation change).
*/
- (void)relayoutAllRows;
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions;
- (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^)())completion; - (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^)())completion;

View File

@ -555,6 +555,26 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
}]; }];
} }
- (void)relayoutAllRows
{
[self performEditCommandWithBlock:^{
ASDisplayNodeAssertMainThread();
LOG(@"Edit Command - relayoutRows");
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
NSArray *indexPaths = ASIndexPathsForMultidimensionalArray(_completedNodes);
NSArray *loadedNodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(_completedNodes, indexPaths);
for (NSUInteger i = 0; i < loadedNodes.count && i < indexPaths.count; i++) {
// TODO: The current implementation does not make use of different constrained sizes per node.
CGSize constrainedSize = [_dataSource dataController:self constrainedSizeForNodeAtIndexPath:indexPaths[i]];
ASCellNode *node = loadedNodes[i];
[node measure:constrainedSize];
node.frame = CGRectMake(0.0f, 0.0f, node.calculatedSize.width, node.calculatedSize.height);
}
}];
}
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{ {
[self performEditCommandWithBlock:^{ [self performEditCommandWithBlock:^{

View File

@ -24,4 +24,8 @@ CGFloat ASCeilPixelValue(CGFloat f);
CGFloat ASRoundPixelValue(CGFloat f); CGFloat ASRoundPixelValue(CGFloat f);
BOOL ASSystemVersionLessThan8();
BOOL ASSystemVersionLessThanVersion(NSString *version);
ASDISPLAYNODE_EXTERN_C_END ASDISPLAYNODE_EXTERN_C_END

View File

@ -61,3 +61,18 @@ CGFloat ASRoundPixelValue(CGFloat f)
{ {
return roundf(f * ASScreenScale()) / ASScreenScale(); return roundf(f * ASScreenScale()) / ASScreenScale();
} }
BOOL ASSystemVersionLessThan8()
{
static BOOL lessThan8;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
lessThan8 = ASSystemVersionLessThanVersion(@"8");
});
return lessThan8;
}
BOOL ASSystemVersionLessThanVersion(NSString *version)
{
return [[[UIDevice currentDevice] systemVersion] compare:version options:NSNumericSearch] == NSOrderedAscending;
}