From 5d61b2b4e66cd3ff08a19a197045162397eac034 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 17 Nov 2016 17:00:23 -0800 Subject: [PATCH] Address further comments --- AsyncDisplayKit/ASDisplayNode.h | 10 ++++++--- AsyncDisplayKit/ASDisplayNode.mm | 21 ++++++++++--------- AsyncDisplayKit/ASTableView.mm | 5 ----- .../Private/ASDisplayNode+FrameworkPrivate.h | 2 +- .../Sample/ViewController.m | 1 - .../Sample/DetailViewController.m | 11 +++++----- .../Sample/SampleSizingNode.m | 2 +- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 67f96f5c4e..6e31d5154f 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -306,7 +306,6 @@ extern NSInteger const ASDefaultDrawingPriority; */ @property (nonatomic, readonly, assign) ASSizeRange constrainedSizeForCalculatedLayout; - /** @name Managing the nodes hierarchy */ @@ -632,13 +631,18 @@ extern NSInteger const ASDefaultDrawingPriority; @interface ASDisplayNode (UIViewBridge) /** - * Marks the view as needing display. Convenience for use whether the view / layer is loaded or not. Safe to call - * from a background thread. + * Marks the view as needing display. Convenience for use whether the view / layer is loaded or not. Safe to call from a background thread. */ - (void)setNeedsDisplay; /** * Marks the node as needing layout. Convenience for use whether the view / layer is loaded or not. Safe to call from a background thread. + * + * If the node determines its own desired layout size will change in the next layout pass, it will propagate this + * information up the tree so its parents can have a chance to consider and apply if necessary the new size onto the node. + * + * Note: ASCellNode has special behavior in that calling this method will automatically notify + * the containing ASTableView / ASCollectionView that the cell should be resized, if necessary. */ - (void)setNeedsLayout; diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index c729173491..c9a7466c74 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -704,7 +704,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) #pragma mark - Layout -- (void)invalidateSize +- (void)setNeedsLayoutFromAbove { ASDisplayNodeAssertThreadAffinity(self); @@ -718,7 +718,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) __instanceLock__.unlock(); // Cause supernode's layout to be invalidated // We need to release the lock to prevent a deadlock - [supernode invalidateSize]; + [supernode setNeedsLayoutFromAbove]; return; } @@ -733,8 +733,13 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) constrainedSize = _calculatedDisplayNodeLayout->constrainedSize; } - // Check if the returned layout has a different size as the current bounds + // Perform a measurement pass to get the current layout + // It's important to differentiate between layout and measure pass here. Calling `layoutThatFits:` just perform a + // measure pass and no layout pass immediately. If a layout pass wold be forced via `layoutIfNeeded` it could cause an + // infinite loop as in `__layout` we check if the size changed and we are just to inform the node that the size changed ASLayout *layout = [self layoutThatFits:constrainedSize]; + + // Check if the returned layout has a different size as the current bounds if (CGSizeEqualToSize(oldSize, layout.size) == NO) { // If the size of the layout changes inform our container (e.g ASTableView, ASCollectionView, ASViewController, ...) // that we need it to change our bounds size. @@ -1415,11 +1420,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) [self invalidateCalculatedLayout]; } -- (void)__layoutIfNeeded -{ - // For now this is a no op. -} - - (void)__setNeedsDisplay { BOOL nowDisplay = ASInterfaceStateIncludesDisplay(_interfaceState); @@ -1540,7 +1540,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) // If the size of the new layout to apply did change from the current bounds, invalidate the whole tree up // so the root node can handle a resizing if necessary if (CGSizeEqualToSize(ASCeilSizeValues(bounds.size), pendingLayout->layout.size) == NO) { - [self invalidateSize]; + [self setNeedsLayoutFromAbove]; } if (didCreateNewContext) { @@ -1570,7 +1570,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) CGRect bounds = self.threadSafeBounds; // Checkout if constrained size of pending or calculated display node layout can be used - if (_pendingDisplayNodeLayout != nullptr && CGSizeEqualToSize(_pendingDisplayNodeLayout->layout.size, ASCeilSizeValues(bounds.size))) { + if (_pendingDisplayNodeLayout != nullptr && + CGSizeEqualToSize(_pendingDisplayNodeLayout->layout.size, ASCeilSizeValues(bounds.size))) { // We assume the size from the last returned layoutThatFits: layout was applied so use the pending display node // layout constrained size return _pendingDisplayNodeLayout->constrainedSize; diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 69ec54dc54..aca1855e7b 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -1567,11 +1567,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } } -- (ASSizeRange)constrainedSizeForNode:(ASCellNode *)node -{ - return [self dataController:self.dataController constrainedSizeForNodeAtIndexPath:[self indexPathForNode:node]]; -} - - (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged { ASDisplayNodeAssertMainThread(); diff --git a/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h b/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h index cefa27e858..dc22cdf736 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h +++ b/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h @@ -181,7 +181,7 @@ __unused static NSString * _Nonnull NSStringFromASHierarchyState(ASHierarchyStat * @discussion The size of a root node is determined by each subnode. Calling invalidateSize will let the root node know * that the intrinsic size of the receiver node is no longer valid and a resizing of the root node needs to happen. */ -- (void)invalidateSize; +- (void)setNeedsLayoutFromAbove; /** * @abstract Subclass hook for nodes that are acting as root nodes. This method is called if one of the subnodes diff --git a/examples/ASDKLayoutTransition/Sample/ViewController.m b/examples/ASDKLayoutTransition/Sample/ViewController.m index eb15153b63..789d5029c4 100644 --- a/examples/ASDKLayoutTransition/Sample/ViewController.m +++ b/examples/ASDKLayoutTransition/Sample/ViewController.m @@ -84,7 +84,6 @@ - (void)buttonPressed:(id)sender { self.enabled = !self.enabled; - [self transitionLayoutWithAnimation:YES shouldMeasureAsync:NO measurementCompletion:nil]; } diff --git a/examples/ASViewController/Sample/DetailViewController.m b/examples/ASViewController/Sample/DetailViewController.m index a838ba645d..c22357036e 100644 --- a/examples/ASViewController/Sample/DetailViewController.m +++ b/examples/ASViewController/Sample/DetailViewController.m @@ -105,11 +105,12 @@ - (void)updateButtonNodeLayout { - [self.buttonNode sizeToFit]; - self.buttonNode.frame = CGRectMake((self.view.bounds.size.width - self.buttonNode.bounds.size.width) / 2.0, + //[self.buttonNode sizeToFit]; + CGSize size = [self.buttonNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY))].size; + self.buttonNode.frame = CGRectMake((self.view.bounds.size.width - size.width) / 2.0, 100, - self.buttonNode.bounds.size.width, - self.buttonNode.bounds.size.height); + size.width, + size.height); //CGSize s = [self.buttonNode sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; //self.buttonNode.frame = CGRectMake(100, 100, s.width, s.height); @@ -141,7 +142,7 @@ //return; // Use the bounds of the view and get the fitting size // This does not have any side effects, but can be called on the main thread without any problems - CGSize size = [self.sizingNode sizeThatFits:CGSizeMake(INFINITY, 100.0)]; + CGSize size = [self.sizingNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, 100.0))].size; //size.width -= 10; //[self.sizingNode setNeedsLayout]; self.sizingNode.frame = CGRectMake((CGRectGetWidth(self.view.bounds) - size.width) / 2.0, diff --git a/examples/ASViewController/Sample/SampleSizingNode.m b/examples/ASViewController/Sample/SampleSizingNode.m index 674b545b09..d7ff1c4e86 100644 --- a/examples/ASViewController/Sample/SampleSizingNode.m +++ b/examples/ASViewController/Sample/SampleSizingNode.m @@ -129,7 +129,7 @@ /*if ([self.sizingDelegate respondsToSelector:@selector(displayNodeDidInvalidateSize:)]) { [self.sizingDelegate performSelector:@selector(displayNodeDidInvalidateSize:) withObject:self]; }*/ - [self invalidateSize]; + //[self invalidateSize]; } #pragma mark - ASDisplayNode