diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index d6fa28ebc2..8223d5208e 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -125,7 +125,7 @@ static BOOL _isInterceptedSelector(SEL sel) ASBatchContext *_batchContext; - BOOL _pendingRelayoutForAllRows; + CGSize _maxSizeForNodesConstrainedSize; } @property (atomic, assign) BOOL asyncDataSourceLocked; @@ -170,16 +170,13 @@ static BOOL _isInterceptedSelector(SEL sel) _performingBatchUpdates = NO; _batchUpdateBlocks = [NSMutableArray array]; + + _collectionViewLayoutImplementsInsetSection = [layout respondsToSelector:@selector(sectionInset)]; + + _maxSizeForNodesConstrainedSize = self.bounds.size; [self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"_ASCollectionViewCell"]; - if (ASSystemVersionLessThan8()) { - [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil]; - } - - _collectionViewLayoutImplementsInsetSection = [layout respondsToSelector:@selector(sectionInset)]; - return self; } @@ -189,11 +186,6 @@ static BOOL _isInterceptedSelector(SEL sel) // This bug might be iOS 7-specific. super.delegate = nil; super.dataSource = nil; - - if (ASSystemVersionLessThan8()) { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; - } } #pragma mark - @@ -480,26 +472,12 @@ 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; + if (! CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, self.bounds.size)) { + _maxSizeForNodesConstrainedSize = self.bounds.size; [self performBatchAnimated:NO updates:^{ [_dataController relayoutAllRows]; } completion:nil]; @@ -562,7 +540,7 @@ static BOOL _isInterceptedSelector(SEL sel) if (_asyncDataSourceImplementsConstrainedSizeForNode) { constrainedSize = [_asyncDataSource collectionView:self constrainedSizeForNodeAtIndexPath:indexPath]; } else { - CGSize maxSize = self.bounds.size; + CGSize maxSize = _maxSizeForNodesConstrainedSize; if (ASScrollDirectionContainsHorizontalDirection([self scrollableDirections])) { maxSize.width = FLT_MAX; } else { diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 32d284f587..06b00c56b9 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -131,10 +131,11 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) { if (ASDisplayNodeSubclassOverridesSelector(c, @selector(touchesEnded:withEvent:))) { overrides |= ASDisplayNodeMethodOverrideTouchesEnded; } - if (ASDisplayNodeSubclassOverridesSelector(c, @selector(calculateSizeThatFits:))) { - overrides |= ASDisplayNodeMethodOverrideCalculateSizeThatFits; + if (ASDisplayNodeSubclassOverridesSelector(c, @selector(layoutSpecThatFits:))) { + overrides |= ASDisplayNodeMethodOverrideLayoutSpecThatFits; } + return overrides; } @@ -1379,10 +1380,7 @@ static NSInteger incrementIfFound(NSInteger i) { - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize { ASDisplayNodeAssertThreadAffinity(self); - if (_methodOverrides & ASDisplayNodeMethodOverrideCalculateSizeThatFits) { - CGSize size = [self calculateSizeThatFits:constrainedSize.max]; - return [ASLayout newWithLayoutableObject:self size:ASSizeRangeClamp(constrainedSize, size)]; - } else { + if (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) { id layoutSpec = [self layoutSpecThatFits:constrainedSize]; ASLayout *layout = [layoutSpec measureWithSizeRange:constrainedSize]; // Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct. @@ -1393,6 +1391,11 @@ static NSInteger incrementIfFound(NSInteger i) { return [layout flattenedLayoutUsingPredicateBlock:^BOOL(ASLayout *evaluatedLayout) { return [_subnodes containsObject:evaluatedLayout.layoutableObject]; }]; + } else { + // If neither -layoutSpecThatFits: nor -calculateSizeThatFits: is overridden by subclassses, preferredFrameSize should be used, + // assume that the default implementation of -calculateSizeThatFits: returns it. + CGSize size = [self calculateSizeThatFits:constrainedSize.max]; + return [ASLayout newWithLayoutableObject:self size:ASSizeRangeClamp(constrainedSize, size)]; } } @@ -1429,7 +1432,10 @@ static NSInteger incrementIfFound(NSInteger i) { - (void)setPreferredFrameSize:(CGSize)preferredFrameSize { ASDN::MutexLocker l(_propertyLock); - _preferredFrameSize = preferredFrameSize; + if (! CGSizeEqualToSize(_preferredFrameSize, preferredFrameSize)) { + _preferredFrameSize = preferredFrameSize; + [self invalidateCalculatedLayout]; + } } - (CGSize)preferredFrameSize diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index cf45cc5320..6a9a3bd339 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -146,9 +146,9 @@ static BOOL _isInterceptedSelector(SEL sel) NSIndexPath *_contentOffsetAdjustmentTopVisibleRow; CGFloat _contentOffsetAdjustment; - BOOL _pendingRelayoutForAllRows; - BOOL _asyncDataSourceImplementsConstrainedSizeForNode; + + CGFloat _maxWidthForNodesConstrainedSize; } @property (atomic, assign) BOOL asyncDataSourceLocked; @@ -202,10 +202,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) { _automaticallyAdjustsContentOffset = NO; - if (ASSystemVersionLessThan8()) { - [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil]; - } + _maxWidthForNodesConstrainedSize = self.bounds.size.width; } - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style @@ -243,11 +240,6 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) { // This bug might be iOS 7-specific. super.delegate = nil; super.dataSource = nil; - - if (ASSystemVersionLessThan8()) { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; - } } #pragma mark - @@ -373,25 +365,12 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) { [_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; + if (_maxWidthForNodesConstrainedSize != self.bounds.size.width) { + _maxWidthForNodesConstrainedSize = self.bounds.size.width; [self beginUpdates]; [_dataController relayoutAllRows]; [self endUpdates]; @@ -812,7 +791,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) { } // Default size range - return ASSizeRangeMake(CGSizeZero, CGSizeMake(self.bounds.size.width, FLT_MAX)); + return ASSizeRangeMake(CGSizeZero, CGSizeMake(_maxWidthForNodesConstrainedSize, FLT_MAX)); } - (void)dataControllerLockDataSource diff --git a/AsyncDisplayKit/Details/ASDataController.h b/AsyncDisplayKit/Details/ASDataController.h index 7221d688cf..68e586daa8 100644 --- a/AsyncDisplayKit/Details/ASDataController.h +++ b/AsyncDisplayKit/Details/ASDataController.h @@ -156,8 +156,8 @@ typedef NSUInteger ASDataControllerAnimationOptions; - (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). + * Re-measures all loaded nodes. Used to respond to a change in size of the containing view + * (e.g. ASTableView or ASCollectionView after an orientation change). */ - (void)relayoutAllRows; diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 4d3d42fcc7..4cfc03270d 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -564,15 +564,14 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; 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++) { - ASSizeRange constrainedSize = [_dataSource dataController:self constrainedSizeForNodeAtIndexPath:indexPaths[i]]; - ASCellNode *node = loadedNodes[i]; - [node measureWithSizeRange:constrainedSize]; - node.frame = CGRectMake(0.0f, 0.0f, node.calculatedSize.width, node.calculatedSize.height); - } + [_completedNodes enumerateObjectsUsingBlock:^(NSMutableArray *section, NSUInteger sectionIndex, BOOL *stop) { + [section enumerateObjectsUsingBlock:^(ASCellNode *node, NSUInteger rowIndex, BOOL *stop) { + ASSizeRange constrainedSize = [_dataSource dataController:self + constrainedSizeForNodeAtIndexPath:[NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex]]; + [node measureWithSizeRange:constrainedSize]; + node.frame = CGRectMake(0.0f, 0.0f, node.calculatedSize.width, node.calculatedSize.height); + }]; + }]; }]; } diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index 309cd08f0b..f9d9556d6a 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -28,7 +28,7 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) { ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1, ASDisplayNodeMethodOverrideTouchesEnded = 1 << 2, ASDisplayNodeMethodOverrideTouchesMoved = 1 << 3, - ASDisplayNodeMethodOverrideCalculateSizeThatFits = 1 << 4 + ASDisplayNodeMethodOverrideLayoutSpecThatFits = 1 << 4 }; @class _ASPendingState; diff --git a/AsyncDisplayKit/Private/ASInternalHelpers.h b/AsyncDisplayKit/Private/ASInternalHelpers.h index b0530db7f7..6a9d74e97e 100644 --- a/AsyncDisplayKit/Private/ASInternalHelpers.h +++ b/AsyncDisplayKit/Private/ASInternalHelpers.h @@ -25,8 +25,4 @@ CGFloat ASCeilPixelValue(CGFloat f); CGFloat ASRoundPixelValue(CGFloat f); -BOOL ASSystemVersionLessThan8(); - -BOOL ASSystemVersionLessThanVersion(NSString *version); - ASDISPLAYNODE_EXTERN_C_END diff --git a/AsyncDisplayKit/Private/ASInternalHelpers.mm b/AsyncDisplayKit/Private/ASInternalHelpers.mm index ddfcaf5d82..f57450d39e 100644 --- a/AsyncDisplayKit/Private/ASInternalHelpers.mm +++ b/AsyncDisplayKit/Private/ASInternalHelpers.mm @@ -70,18 +70,3 @@ CGFloat ASRoundPixelValue(CGFloat f) { 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; -} diff --git a/examples/Kittens/Sample.xcodeproj/project.pbxproj b/examples/Kittens/Sample.xcodeproj/project.pbxproj index fde58763d9..293b513d1e 100644 --- a/examples/Kittens/Sample.xcodeproj/project.pbxproj +++ b/examples/Kittens/Sample.xcodeproj/project.pbxproj @@ -314,6 +314,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -326,6 +327,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; diff --git a/examples/Kittens/Sample/ViewController.m b/examples/Kittens/Sample/ViewController.m index 02760a6355..7989fe15ce 100644 --- a/examples/Kittens/Sample/ViewController.m +++ b/examples/Kittens/Sample/ViewController.m @@ -59,6 +59,7 @@ static const NSInteger kMaxLitterSize = 100; // max number of kitten cell _blurbNodeIndexPath = [NSIndexPath indexPathForItem:0 inSection:0]; + self.title = @"Kittens"; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(toggleEditingMode)];