From b4d490848fd7cedeec22dc5412bf9e456ec8a672 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Tue, 17 May 2016 11:49:27 +0200 Subject: [PATCH 1/3] Add measure: call for nodes without host on themselves if developer does not Normally measure will be called before layout occurs. If this doesn't happen, nothing is going to call it at all. An experimenting developer probably added a node to the hierarchy directly. We simply call measureWithSizeRange: using a size range equal to whatever bounds were provided to that element. This make initial experimentation using layoutSpecs much easier. Furthermore added logging if no size is given for the node before layout occurs. --- AsyncDisplayKit/ASDisplayNode.mm | 71 +++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index a06b8bf352..8cf5137719 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1074,19 +1074,58 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) ASDisplayNodeAssertMainThread(); ASDN::MutexLocker l(_propertyLock); CGRect bounds = self.bounds; - if (CGRectEqualToRect(bounds, CGRectZero)) { - // Performing layout on a zero-bounds view often results in frame calculations - // with negative sizes after applying margins, which will cause - // measureWithSizeRange: on subnodes to assert. + + [self measureNodeWithBoundsIfNecessary:bounds]; + + // Performing layout on a zero-bounds view often results in frame calculations + // with negative sizes after applying margins, which will cause + // measureWithSizeRange: on subnodes to assert. + if (!CGRectEqualToRect(bounds, CGRectZero)) { + _placeholderLayer.frame = bounds; + [self layout]; + [self layoutDidFinish]; + } +} + +- (void)measureNodeWithBoundsIfNecessary:(CGRect)bounds +{ + // Normally measure will be called before layout occurs. If this doesn't happen, nothing is going to call it at all. + // We simply call measureWithSizeRange: using a size range equal to whatever bounds were provided to that element or + // try to measure the node with the largest size as possible + if (self.supernode == nil && !self.supportsRangeManagedInterfaceState && !_flags.isMeasured) { + if (CGRectEqualToRect(bounds, CGRectZero)) { + // FIXME: Better log to let developers know that the node was not measured before the layout call and no frame was set + NSLog(@"Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self); + } else { + ASSizeRange measureSizeRange = ASSizeRangeMake(CGSizeZero, bounds.size); + if ([self shouldMeasureWithSizeRange:measureSizeRange]) { + [self measureWithSizeRange:measureSizeRange]; + } + } + } +} + +- (void)layout +{ + ASDisplayNodeAssertMainThread(); + + if (!_flags.isMeasured) { return; } - _placeholderLayer.frame = bounds; - [self layout]; - [self layoutDidFinish]; + + [self __layoutSublayouts]; +} + +- (void)__layoutSublayouts +{ + for (ASLayout *subnodeLayout in _layout.immediateSublayouts) { + ((ASDisplayNode *)subnodeLayout.layoutableObject).frame = [subnodeLayout frame]; + } } - (void)layoutDidFinish { + // Hook for subclasses } - (CATransform3D)_transformToAncestor:(ASDisplayNode *)ancestor @@ -2369,24 +2408,6 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) } } -- (void)layout -{ - ASDisplayNodeAssertMainThread(); - - if (!_flags.isMeasured) { - return; - } - - [self __layoutSublayouts]; -} - -- (void)__layoutSublayouts -{ - for (ASLayout *subnodeLayout in _layout.immediateSublayouts) { - ((ASDisplayNode *)subnodeLayout.layoutableObject).frame = [subnodeLayout frame]; - } -} - - (void)displayWillStart { ASDisplayNodeAssertMainThread(); From ecd7727ceb51cae3f6e0da3fe6df77c69ea66aaf Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Tue, 17 May 2016 11:49:59 +0200 Subject: [PATCH 2/3] Update Videos example to leverage automatic measure: call before layout --- examples/Videos/Sample/ViewController.m | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/examples/Videos/Sample/ViewController.m b/examples/Videos/Sample/ViewController.m index db1f18659d..ba1323441d 100644 --- a/examples/Videos/Sample/ViewController.m +++ b/examples/Videos/Sample/ViewController.m @@ -28,6 +28,7 @@ // Root node for the view controller _rootNode = [ASDisplayNode new]; + _rootNode.frame = self.view.bounds; _rootNode.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; ASVideoNode *guitarVideoNode = self.guitarVideoNode; @@ -54,16 +55,6 @@ [self.view addSubnode:_rootNode]; } -- (void)viewDidLayoutSubviews -{ - [super viewDidLayoutSubviews]; - - // After all subviews are layed out we have to measure it and move the root node to the right place - CGSize viewSize = self.view.bounds.size; - [self.rootNode measureWithSizeRange:ASSizeRangeMake(viewSize, viewSize)]; - [self.rootNode setNeedsLayout]; -} - #pragma mark - Getter / Setter - (ASVideoNode *)guitarVideoNode; From 691749d098b86ebda8ea340ad82695bc8e0ba895 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Fri, 3 Jun 2016 13:24:24 -0700 Subject: [PATCH 3/3] Address comments --- AsyncDisplayKit/ASDisplayNode.h | 2 ++ AsyncDisplayKit/ASDisplayNode.mm | 15 +++++++-------- examples/Videos/Sample/ViewController.h | 4 ++-- examples/Videos/Sample/ViewController.m | 17 +++++++++++++---- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 7c53e93a05..ff63eeee2d 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -15,6 +15,8 @@ #import #import +#define ASDisplayNodeLoggingEnabled 0 + @class ASDisplayNode; /** diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 8cf5137719..355ec6f460 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -48,8 +48,11 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS @end -//#define LOG(...) NSLog(__VA_ARGS__) -#define LOG(...) +#if ASDisplayNodeLoggingEnabled + #define LOG(...) NSLog(__VA_ARGS__) +#else + #define LOG(...) +#endif // Conditionally time these scopes to our debug ivars (only exist in debug/profile builds) #if TIME_DISPLAYNODE_OPS @@ -1094,13 +1097,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) // try to measure the node with the largest size as possible if (self.supernode == nil && !self.supportsRangeManagedInterfaceState && !_flags.isMeasured) { if (CGRectEqualToRect(bounds, CGRectZero)) { - // FIXME: Better log to let developers know that the node was not measured before the layout call and no frame was set - NSLog(@"Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self); + LOG(@"Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self); } else { - ASSizeRange measureSizeRange = ASSizeRangeMake(CGSizeZero, bounds.size); - if ([self shouldMeasureWithSizeRange:measureSizeRange]) { - [self measureWithSizeRange:measureSizeRange]; - } + [self measureWithSizeRange:ASSizeRangeMake(CGSizeZero, bounds.size)]; } } } diff --git a/examples/Videos/Sample/ViewController.h b/examples/Videos/Sample/ViewController.h index 1664a00082..7549a97db6 100644 --- a/examples/Videos/Sample/ViewController.h +++ b/examples/Videos/Sample/ViewController.h @@ -8,8 +8,8 @@ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#import -#import + +#include @interface ViewController : UIViewController diff --git a/examples/Videos/Sample/ViewController.m b/examples/Videos/Sample/ViewController.m index ba1323441d..289d5443d4 100644 --- a/examples/Videos/Sample/ViewController.m +++ b/examples/Videos/Sample/ViewController.m @@ -10,8 +10,7 @@ */ #import "ViewController.h" -#import "ASLayoutSpec.h" -#import "ASStaticLayoutSpec.h" +#import @interface ViewController() @property (nonatomic, strong) ASDisplayNode *rootNode; @@ -22,10 +21,20 @@ #pragma mark - UIViewController -- (void)viewWillAppear:(BOOL)animated +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { - [super viewWillAppear:animated]; + self = [super initWithNibName:nil bundle:nil]; + if (self) { + + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Root node for the view controller _rootNode = [ASDisplayNode new]; _rootNode.frame = self.view.bounds;